简单工厂的本质是,工厂根据传入的参数,动态的决定应该使用哪个产品(产品是接口的具体实现)。其中涉及三类角色:java
(1)工厂角色。负责建立全部实例。工厂类中建立产品类的方法能够被外界直接调用,建立所需的产品对象。web
(2)抽象产品角色。简单工厂模式所建立的全部对象的父类,负责描述全部实例共有的公共接口。c#
(3)具体产品角色。是简单工厂模式的建立目标,全部建立的对象都是充当这个角色的某个具体类的实例。 设计模式
场景描述:使用c#、java、c、VB任意一种语言实现一个计算器控制台应用程序,要求输入两个数和运算符号,获得结果。ide
class Program { static void Main(string[] args) { Console.WriteLine("请输入数字1"); string num1 = Console.ReadLine(); Console.WriteLine("请输入数字2"); string num2 = Console.ReadLine(); Console.WriteLine("请输入运算符号"); string sysbol = Console.ReadLine(); string result = ""; switch (sysbol) { case "+":result = Convert.ToString(Convert.ToDouble(num1)+Convert.ToDouble(num2)); break; case "-":result = Convert.ToString(Convert.ToDouble(num1) - Convert.ToDouble(num2)); break; case "*": result = Convert.ToString(Convert.ToDouble(num1) * Convert.ToDouble(num2)); break; case "/": result = Convert.ToString(Convert.ToDouble(num1) / Convert.ToDouble(num2)); break; } Console.WriteLine("result={0}",result); Console.OutputEncoding = Encoding.UTF8; } }
目前来讲,实现加减乘除的功能已经实现,然而程序不易维护扩展,更不易复用。于是,咱们能够考虑经过封装、继承、多态把程序的耦合度下降,用设计模式令程序更加灵活易修改。优化
假设此时想要写一个Windows的计算器方法,则目前的代码就没法复用,那么咱们能够考虑将计算器的实现部分和控制台的输出部分进行分离,即让业务逻辑和界面逻辑分开,减低他们的耦合度达到易维护易扩展。此时,计算器的实现部分就可实现复用。spa
class compute { public static double getResult(double num1,double num2,string operation) { double result = 0.0; switch (operation) { case "+": result = num1 + num2; break; case "-": result = num1 - num2; break; case "*": result = num1 * num2; break; case "/": if (num2 != 0) result = num1 / num2; else Console.Write("除数不能为0"); break; } return result; } }
static void Main(string[] args) { Console.WriteLine("请输入数字1"); string num1 = Console.ReadLine(); Console.WriteLine("请输入数字2"); string num2 = Console.ReadLine(); Console.WriteLine("请输入运算符号"); string sysbol = Console.ReadLine(); string result = Convert.ToString(compute.getResult(Convert.ToInt32(num1), Convert.ToInt32(num2), sysbol)); Console.WriteLine("Hello World!"); }
上述代码虽然实现了控制器与具体方法实现的解耦(界面分离),但若是须要增长其余运算符号时,依然须要编译已写好的代码,此时可能致使修改时会令原有正常运行的代码在修改时不当心改动发生错误。于是,咱们能够考虑建立一个运算类(父类),令其余加减乘除的运算类继承他,从而达到修改或增长较少一个子类不影响其余类的运行。设计
class Operate { public int _num1; public int _num2; public double num1 { get { return _num1; } set { num1 = _num1; } } public double num2 { get { return _num2; } set { num2 = _num2; } } public virtual double getResult(double n1,double n2) { double result = 0.0; return result; } } class Add:Operate { public override double getResult(double n1, double n2) { return n1 + n2; } } class Sub : Operate { public override double getResult(double n1, double n2) { return n1 - n2; } } class Multiply : Operate { public override double getResult(double n1, double n2) { return n1 * n2; } } class Divide: Operate { public override double getResult(double n1, double n2) {
if (n2 == 0)
throw new Exception("除数不能为0");
return n1 / n2;code
}对象
}
static void Main(string[] args) { Console.WriteLine("请输入数字1"); string num1 = Console.ReadLine(); Console.WriteLine("请输入数字2"); string num2 = Console.ReadLine(); Operate sysbol = new Add(); double result= sysbol.getResult(Convert.ToDouble(num1),Convert.ToDouble(num2)); Console.WriteLine("{0}", result); }
上述代码实现了类的分离,并可以根据对象实例化,可是必须知道须要调用哪一个类,没法根据输入的符号进行判断。所以,如何实现对象实例化,实例化谁,未来要增长的运算怎么处理,将这些用一个单独的工厂类实现。完整代码以下:
class Operate { public int _num1; public int _num2; public double num1 { get { return _num1; } set { num1 = _num1; } } public double num2 { get { return _num2; } set { num2 = _num2; } } public virtual double getResult(double n1,double n2) { double result = 0.0; return result; } } class Add:Operate { public override double getResult(double n1, double n2) { return n1 + n2; } } class Sub : Operate { public override double getResult(double n1, double n2) { return n1 - n2; } } class Multiply : Operate { public override double getResult(double n1, double n2) { return n1 * n2; } } class Divide: Operate { public override double getResult(double n1, double n2) { if (n2 == 0) throw new Exception("除数不能为0"); return n1 / n2; } } class Factory { /// <summary> /// 工厂经过输入符号实例化对象 /// </summary> /// <param name="operation">运算符号</param> /// <returns></returns> public static Operate createOperate(string operation) { Operate oper = null; switch (operation) { case "+": oper = new Add();break; case "-":oper = new Sub();break; case "*": oper = new Multiply();break; case "/":oper = new Divide();break; } return oper; } } class Program { static void Main(string[] args) { Console.WriteLine("请输入数字1"); string num1 = Console.ReadLine(); Console.WriteLine("请输入数字2"); string num2 = Console.ReadLine(); Operate ope = Factory.createOperate("+"); double result= ope.getResult(Convert.ToDouble(num1), Convert.ToDouble(num2)); Console.WriteLine("{0}",result); } }
这种实现中,只需输入运算符号,工厂就能够实例化出合适的对象,经过多态返回父类的方式实现了计算器的结果。此时,不管是控制台程序、Windows程序、web程序或其余手机程序,均可以用上述的工厂方法和运算类。须要增长运算时,只需再增长一个子类继承Operation,并在工厂方法的switch中添加一个分支便可。封装、继承、多态是面向对象的3大特性,也是理解设计模式的基础。
简单工厂模式主要适用于抽象子类的业务逻辑相同,但具体实现不一样的状况。不一样的操做子类执行一样的方法。如以上给出的实现计算器功能,运算的操做都是针对两个数和一个运算方法,只是运算操做不一样,就可使用简单工厂模式。例如,一我的想 开车,家里有多种类型的车(如跑车、越野车、两厢车),它们都能实现跑(run)的功能,选择哪一辆车即对哪一个对象实例化,因为可能还会增长或减小车,咱们考虑用一个类建立实例。也是简单工厂的应用。
优势:
缺点:须要增长一个具体对象时,须要在工厂类中增减代码,违背了面向对象设计的“开放-封闭”原则;
简单工厂建立子类实例并传给外界时只须要知道抽象子类对应的参数便可,而不须要知道抽象子类的建立过程,在外界使用时甚至不用引入抽象子类。简单工厂明确区分了各个子类的职责和权力,有利于整个软件体系的优化。
主要参考:《大话设计模式》