一、简单工厂
实现如下:
1 //计算器总的抽象类 2 public abstract class Computer 3 { 4 private int _NumberA; 5 private int _NumberB; 6 public int NumberA 7 { 8 set { 9 _NumberA = value; 10 } 11 get 12 { 13 return _NumberA; 14 } 15 } 16 17 public int NumberB 18 { 19 set 20 { 21 _NumberB = value; 22 } 23 get 24 { 25 return _NumberB; 26 } 27 } 28 29 public abstract int Result 30 { 31 get; 32 } 33 } 34 //加法计算器类 35 public class JiaComputer:Computer 36 { 37 38 public override int Result 39 { 40 get { return base.NumberA + base.NumberB; } 41 } 42 } 43 //减法计算器类 44 public class JianComouter : Computer 45 { 46 public override int Result 47 { 48 get { return base.NumberA - base.NumberB; } 49 } 50 } 51 //乘法计算器类 52 public class ChenComputer : Computer 53 { 54 public override int Result 55 { 56 get { return base.NumberA * base.NumberB; } 57 } 58 } 59 //除法计算器类 60 public class ChuComputer : Computer 61 { 62 public override int Result 63 { 64 get { return base.NumberA / base.NumberB; } 65 } 66 }
在主函数中调用的代码如下:
1 Console.WriteLine("请输入第一个数字"); 2 int a = int.Parse(Console.ReadLine()); 3 Console.WriteLine("请输入第二个数字!"); 4 int b = int.Parse(Console.ReadLine()); 5 Console.WriteLine("请输入操作符"); 6 string op = Console.ReadLine(); 7 8 int result = 0; 9 //使用这种方法,重复性 很大,还有 如果增加了一个运算符的话 ,修改 用户层了,这样的耦合 太强了 10 switch (op) 11 { 12 case "+": 13 AddCompter com = new AddCompter(); 14 com.NumberA = a; 15 com.NumberB = b; 16 result = com.Result; 17 break; 18 case "-": 19 AddCompter com2 = new AddCompter(); 20 com2.NumberA = a; 21 com2.NumberB = b; 22 result = com2.Result; 23 break; 24 case "*": 25 AddCompter com3 = new AddCompter(); 26 com3.NumberA = a; 27 com3.NumberB = b; 28 result = com3.Result; 29 break; 30 case "/": 31 AddCompter com4 = new AddCompter(); 32 com4.NumberA = a; 33 com4.NumberB = b; 34 result = com4.Result; 35 break; 36 37 default: 38 break; 39 }
使用简单工厂,将创建计算器的过程封装到工厂里面去,使用的时候直接从工厂中调用对应的方法直接调用就可以了;而且扩展的话很容易,因为将创建过程封装起来的,不需要修改客户端代码,增强代码的健壮性。
结构图:
代码:
1 public class SimFactory 2 { 3 //此方法将复杂度封装起来了,将创建和表示相分离。。用户不必知道内部是怎么实现的。。 4 //这样不管在增加几个运算符的类,不管后期怎么扩展,只要实现抽象类Computer,只需要在此方法内增加一个就可以,,用户界面不许修改,将变化封装起来了。 5 public static Computer GetCom(string op) 6 { 7 Computer com =null; 8 switch (op) 9 { 10 case "+": 11 com = new JiaComputer(); 12 break; 13 case "-": 14 com = new JianComouter(); 15 break; 16 case "*": 17 com = new ChenComputer(); 18 break; 19 case "/": 20 com = new ChuComputer(); 21 break; 22 default: 23 break; 24 } 25 return com; 26 27 } 28 }
主函数调用代码:
Console.WriteLine("请输入第一个数字"); int a = int.Parse(Console.ReadLine()); Console.WriteLine("请输入第二个数字!"); int b = int.Parse(Console.ReadLine()); Console.WriteLine("请输入操作符"); string op = Console.ReadLine(); int result = 0; //不管 在增加 几个运算类 ,用户层都不会更改 Computer com = SimFactory.GetCom(op); com.NumberA = a; com.NumberB = b; result = com.Result; Console.WriteLine(result);
二、工厂方法
简单工厂其不是设计模式,只是向工厂方法和抽象工厂的过度的一个过程。
出现原因:
1、在软件系统中,面临着一个对象的“创建工作”;由于需求的变化,这个复杂的对象经常发生剧烈的变化,但是却拥有稳定的创建接口。
2、如何应对这样的变化?如何提供一种“封装机制”来隔离出这个复杂对象的变化 ,从而是系统中依赖此对象的对象不会随着需求的变化而变化。
意图:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。(将每个对象的创建延迟到每个对应的子工厂)
结构图:
代码:
1 //这种工厂方法的设计模式:1、全部都是对象之间的操作,创建产品的实例的时候都是在 对象的工厂里面创建的,而不是在过程中创建的,体现了面向对对象的思想 ,体现了封装性的原则(创建对象是在类的内部创建的) 2 //2、将 对象的复杂度都在类内部进行处理了,降低的 耦合度。 3 //3、每个类只执行自己应该做的功能的并且只执行一个工能,体现的单一职责原则,还有迪米特原则,比如工厂就是 创建一个 工厂的实例,没做其他事情。一个子工厂值创建一个 对应的子产品,一个子产品运算符只执行一种运算工能。 4 5 6 /// <summary> 7 /// 最基层的工厂接口,,下面每种产品含有自己对应的一个工厂,在创建的时候找到自己对应的工厂通过FactoryMethod()方法创建就可以了 8 /// </summary> 9 public interface IFactory 10 { 11 //这个就是工厂方法: 12 Computer GetFactoryMethod(); 13 } 14 15 public class AddFactory : IFactory 16 { 17 public Computer GetFactoryMethod() 18 { 19 return new AddCompter(); 20 } 21 } 22 23 public class JianFactory : IFactory 24 { 25 public Computer GetFactoryMethod() 26 { 27 return new JianCompter(); 28 } 29 } 30 31 public class ChengFactory : IFactory 32 { 33 public Computer GetFactoryMethod() 34 { 35 return new ChenCompter(); 36 } 37 } 38 39 public class ChuFactory : IFactory 40 { 41 public Computer GetFactoryMethod() 42 { 43 return new ChuComputer(); 44 } 45 } 46 47 48 49 50 51 public abstract class Computer 52 { 53 private int _NumberA; 54 55 public int NumberA 56 { 57 get { return _NumberA; } 58 set { _NumberA = value; } 59 } 60 private int _NumberB; 61 62 public int NumberB 63 { 64 get { return _NumberB; } 65 set { _NumberB = value; } 66 } 67 68 public string op { set; get; } 69 public abstract int Result 70 { 71 get; 72 } 73 } 74 75 76 public class AddCompter : Computer 77 { 78 79 public override int Result 80 { 81 get 82 { 83 return base.NumberA + base.NumberB; 84 } 85 } 86 } 87 88 public class JianCompter : Computer 89 { 90 public override int Result 91 { 92 get 93 { 94 return base.NumberA - base.NumberB; 95 } 96 } 97 } 98 99 100 public class ChenCompter : Computer 101 { 102 public override int Result 103 { 104 get 105 { 106 return base.NumberA * base.NumberB; 107 } 108 } 109 } 110 111 public class ChuComputer : Computer 112 { 113 public override int Result 114 { 115 get 116 { 117 if (base.NumberB != 0) 118 { 119 return base.NumberA / base.NumberA; 120 } 121 else 122 { 123 throw new Exception("除数不能为0!"); 124 } 125 } 126 } 127 } 128 }
主函数调用:
1 Console.WriteLine("请输入第一个数字"); 2 int a = int.Parse(Console.ReadLine()); 3 Console.WriteLine("请输入第二个数字!"); 4 int b = int.Parse(Console.ReadLine()); 5 Console.WriteLine("请输入操作符"); 6 string op = Console.ReadLine(); 7 8 int result = 0; 9 IFactory factory = null; 10 Computer com = null; 11 switch (op) 12 { 13 case "+": 14 factory = new AddFactory(); 15 break; 16 case "-": 17 factory = new JianFactory(); 18 break; 19 case "*": 20 factory = new ChengFactory(); 21 break; 22 case "/": 23 factory = new ChuFactory(); 24 25 break; 26 default: 27 break; 28 } 29 com = factory.GetFactoryMethod(); 30 com.NumberA = a; 31 com.NumberB = b; 32 result = com.Result; 33 Console.WriteLine(result); 34 Console.ReadKey();
作用:
Factory Method模式的两种情况:一是Creator类是一个抽象类且它不提供它所声明的工厂方法的实现(使用抽象实现的多态);二是Creator是一个具体的类且它提供一个工厂方法的缺省实现(使用的不是抽象,使用的virtual实现的多态)。
工厂方法是可以带参数的。 (比如:获得产品的时候,想要获得其他的一下额外的信息(例如:获得订单类的时候,想要 查出指定的订单,将订单的 编号传进去))
工厂的作用并不仅仅只是创建一个对象,它还可以做对象的初始化,参数的设置等。
效果:
1、用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。 (产品的创建是在对应的子类的工厂里面创建的,体现了面向对象,体现了“封装性”原则)
2、Factory Method模式通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类(子工厂),从而提供了一种扩展的策略(多一个产品就对应多一个工厂),较好的解决了这种紧耦合的关系(创建每一个产品的实例都是在对应的子工厂里面创建的。这样耦合度就大大降低了, 场频那方面更改之后,用户操作 就几乎不用更改。将修改封装)
适用性:
1. 当一个类不知道它所必须创建的对象的类的时候。 (比如:用户要进行运算操作,但是用户不知道用哪一种运算,所以就要将变化封装起来,创建过程用户是不知道的)
2. 当一个类希望由它的子类来指定它所创建的对象的时候。 (就是将创建对象初始化的工作交给子工厂)
3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
总结:
1、Factory Method模式主要用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。
2、Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
三、抽象工厂
出现原因:
1、经常出现创建一系列产品。如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合(怎么降低耦合度:将创建实例延迟到 对应的产品系列的 接口去创建)
2、主要针对的 多种产品的多个系列,注意每个系列之间的产品必须是有依赖性、有关联性的。
意图:
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。(一个系列的产品对应一个对应抽象基工厂,创建这个系列中的不同种产品)
结构图:
代码:
1 //创建两种系列的产品(1、2为系列),每个系列中都有两种产品(A、B两种) 2 //定义两种产品 3 public interface IProductA 4 { 5 6 } 7 8 public interface IProductB 9 { 10 } 11 12 //下面是一种产品的几种类型 13 public class ProductA1:IProductA 14 { 15 } 16 17 public class ProductA2 : IProductA 18 { 19 } 20 21 public class ProductB1 : IProductB 22 { 23 } 24 25 public class ProductB2 : IProductB 26 { 27 } 28 29 30 //下面创建工厂:是针对 系列 进行 创建的 31 public interface IAbsFactory 32 { 33 IProductA CreateProductA(); 34 IProductB CreateProductB(); 35 } 36 37 public class Factory1:IAbsFactory 38 { 39 public IProductA CreateProductA() 40 { 41 return new ProductA1(); 42 } 43 44 public IProductB CreateProductB() 45 { 46 return new ProductB1(); 47 } 48 } 49 50 51 public class Factory2 : IAbsFactory 52 { 53 public IProductA CreateProductA() 54 { 55 return new ProductA2(); 56 } 57 58 public IProductB CreateProductB() 59 { 60 return new ProductB2(); 61 } 62 }
主函数调用:
1 IProductA productA = null; 2 IProductB productB = null; 3 IAbsFactory factory = null; 4 //为两种产品创建 创建地中类型的 产品 5 factory = new Factory1(); 6 productA = factory.CreateProductA(); 7 productB = factory.CreateProductB(); 8 //创建第二种类型的产品 9 factory = new Factory2(); 10 productA = factory.CreateProductA(); 11 productB = factory.CreateProductB(); 12 //在实际项目中,上面的工厂是通过反射动态创建的。
实现要点:
1、抽象工厂将产品对象的创建延迟到它的具体工厂的子类。
2、通常在运行时刻创建一个具体工厂类的实例(通过反射动态创建),这一具体工厂的创建具有特定实现的产品对象,为创建不同的产品对象,客户应使用不同的具体工厂。 (一个系列产品对应创建一个工厂,进而通过工厂创建不同种的产品)
3、把工厂作为单件,一个应用中一般每个产品系列只需一个具体工厂的实例,因此,工厂通常最好实现为一个单件模式。
4、创建产品,抽象工厂仅声明一个创建产品的接口,真正创建产品是由具体工厂类创建的(封装原则),最通常的一个办法是为每一个产品定义一个工厂方法,一个具体的工厂将为每个产品重定义该工厂方法以指定产品,虽然这样的实现很简单,但它要求每个产品系列都要有一个新的具体工厂子类,即使这些产品系列的差别很小。(每个系列都要有一个 工厂的子类 与之对应,并且,每种产品在 工厂里面 都会有与之对应的 一个工厂方法进行创建 他们)
适用性:
1、一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。(应该尽量降低耦合度)
2、这个系统有多于一个的产品族,而系统只消费其中某一产品族。(有多个系列产品,但是系统只会使用其中的一个,将这些产品进行切换使用)
3、同属于同一个产品族的产品是在一起使用的(就是同一系列的产品 之间要有联系、有依赖,需要同时使用。(不要停留在所举的例子:不同品牌的帽子、鞋,这只是为了理解),真正使用的时候同一系列产品之间是用联系的),这一约束必须在系统的设计中体现出来。
4、系统提供一个产品类的库,所有的产品以同样的接口出现(工厂接口下面的具体工厂子类可以创建这个系列的所有产品),从而使客户端不依赖于实现。
总结:
1、如果没有应对“多系列对象构建”(多种产品的多个系列)的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的静态工厂完全可以。
2、“ 系列对象”指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中的“道路”与“房屋”的依赖,“道路”与“地道”的依赖。
(*)3、Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。(抽象工厂 优势:对 新的系列 产品 扩展是非常方便。缺点:但是如果要扩展产品的种类,那就shit了,完全乱了,这个时候就要对 工厂就行修改了,因为所有系列的工厂都要修改(违反了开闭原则))
4、Abstract Factory模式经常和Factory Method模式共同组合来应对“对象创建”的需求变化。(搭建的那个 项目架构就是组合使用,由一个工厂 统一 生产一系列的产品,这些产品是通过工厂方法模式创建出来(使用 反射动态创建))
四、总结
1、Builder模式解决“对象部分”的需求变化,Factory Method模式解决“单个对象”的需求变化,Abstract Factory 模式解决“系列对象”的需求变化。
2、如果不是多个系列的产品的创建,使用简单的静态工厂就可以了。