引言
在上边博客中我提到的工厂设计模式中还存在switch case语句,原文链接:https://blog.csdn.net/weixin_72139050/article/details/134632062
我们这里使用的switch是根据客户的选择去返回对应的操作对象,但是我们的这个写法他是存在弊端的,这样不符合我们的依赖倒置原则,这里我们抽象依赖了细节,所以我们要做出对应的调整。
再上面博客的后面我们进行了优化,使用了工厂方法设计模式,在里面我们使用了抽象类,写了多个类来继承这个抽象类,让我们的细节依赖于抽象,减除了switch case ,但是随之问题产生,在我们的调用端产生了大量的switch case,我们依旧还在判断用户需要什么运算符.我们在这节需要干掉这段冗余代码
思考
Console.WriteLine("请输入第一个操作数:");
double d1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("请输入第二个操作数:");
double d2 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("请输入操作符:");
string ock = Console.ReadLine();
ICallFactory _Icoludoctor = null;
switch (ock)
{
case "+":
_Icoludoctor = new AddFactoay();
break;
case "-":
_Icoludoctor = new JianFactoay();
break;
case "*":
_Icoludoctor = new ChenFactoay();
break;
case "/":
_Icoludoctor = new ChuFactoay();
break;
}
这段switch其实是描述了一种关系:运算符和我们具体工厂对象的对应关系。我们尝试换一种方式来实现这种对应关系
代码实现以及思路
我们通过Attribute来实现,在里面定义一个字符串,并且写一个构造函数,随后我们在每一个具体工厂对象类上面写上语句,然后我们程序运行起来之后,拿到这段关系,并且根据客户的操作返回对应的操作,这里我们通过反射来实现下面附上完整的代码
static void Main(string[] args)
{
Console.WriteLine("请输入第一个操作数:");
double d1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("请输入第二个操作数:");
double d2 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("请输入操作符:");
string ock = Console.ReadLine();
RefConrtilyFactory refConrtilyFactory = new RefConrtilyFactory();
ICallFactory callFactory= refConrtilyFactory.GetFac(ock);
Icoludoctor _ico= callFactory.GetIcoludoctor();
double sum= _ico.GetResult(d1,d2);
Console.WriteLine("答案是:" + sum);
Console.ReadKey();
}
public class OperToFactory:Attribute
{
public string Opr { get; }
public OperToFactory(string s)
{
Opr = s;
}
}
public class RefConrtilyFactory
{
Dictionary<string, ICallFactory> dic = new Dictionary<string, ICallFactory>();
public RefConrtilyFactory()
{
//拿到当前程序运行的程序集
Assembly assembly = Assembly.GetExecutingAssembly();
//我们只需要 AddFactoay JianFactoay ChenFactoay ChenFactoay这四个类
foreach (var item in assembly.GetTypes())
{
//注意这里我们还要加判断,防止吧接口也加进来
if (typeof(ICallFactory).IsAssignableFrom(item)&& !item.IsInterface)
{
//我们拿Attribute
OperToFactory ofc= item.GetCustomAttribute<OperToFactory>();
if (ofc.Opr!=null)
{
dic[ofc.Opr] = Activator.CreateInstance(item) as ICallFactory;
}
}
}
}
//我们回传给客户端具体的哪个工厂对象
public ICallFactory GetFac(string s)
{
if (dic.ContainsKey(s))
{
return dic[s];
}
return null;
}
}
public interface ICallFactory
{
Icoludoctor GetIcoludoctor();
}
[OperToFactory("+")]
public class AddFactoay : ICallFactory
{
public Icoludoctor GetIcoludoctor()
{
return new Add();
}
}
[OperToFactory("-")]
public class JianFactoay : ICallFactory
{
public Icoludoctor GetIcoludoctor()
{
return new Jian();
}
}
[OperToFactory("/")]
public class ChenFactoay : ICallFactory
{
public Icoludoctor GetIcoludoctor()
{
return new Chen();
}
}
[OperToFactory("/")]
public class ChuFactoay : ICallFactory
{
public Icoludoctor GetIcoludoctor()
{
return new Chu();
}
}
/// <summary>
/// 计算类的接口
/// </summary>
public interface Icoludoctor
{
//方法:返回最终结算的结果
double GetResult(double d1, double d2);
}
public class Add : Icoludoctor
{
public double GetResult(double d1, double d2)
{
return d1 + d2;
}
}
public class Jian : Icoludoctor
{
public double GetResult(double d1, double d2)
{
return d1 - d2;
}
}
public class Chen : Icoludoctor
{
public double GetResult(double d1, double d2)
{
return d1 * d2;
}
}
public class Chu : Icoludoctor
{
public double GetResult(double d1, double d2)
{
return d1 / d2;
}
}
我们干掉了switch,但是这样使我们的代码稍微有些许的复杂,但是让我们的代码更加正经了,哈哈,