1.定义
简单工厂模式:是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
工厂模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。
抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
2.实例
用工人种蔬菜的例子来说明,蔬菜植物的产品器官有根、茎、叶、花、果等5类,因此按产品器官分类也分成5种,分别是根菜类,茎菜类,叶莱类,花菜类以及果菜类。我们以根菜类,茎菜类为例,分别用简单工厂模式,工厂模式,抽象工厂模式来实现。先说明一下:根菜类的
植物有:大豆,胡萝卜,大头菜等;茎菜类的植物有:竹笋,莲藕,马铃薯等。下面便是三种模式下种菜的实现过程。
3.实现过程
A.简单工厂模式
1).在根菜类植物中,工人种植大豆,胡萝卜,大头菜,代码如下:
1 namespace 简单工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 根菜类 5 /// </summary> 6 public class RootVegetable 7 { 8 public void PlantVegetable() 9 { 10 Console.WriteLine("亲!我在种植大豆,胡萝卜,还有大头菜哦!"); 11 } 12 } 13 }
在茎菜类植物中,工人种植竹笋,莲藕,马铃薯,代码如下:
1 namespace 简单工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 茎菜类 5 /// </summary> 6 public class StemVegetable 7 { 8 public void PlantVegetable() 9 { 10 Console.WriteLine("亲啊!我在种植竹笋,莲藕,还有马铃薯哦!"); 11 } 12 } 13 }
2)进一步抽象,为它们抽象出共同的父类,蔬菜接口,如图:
抽象后的代码如下:
1 namespace 简单工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 蔬菜接口 5 /// </summary> 6 public abstract class Vegetable 7 { 8 public abstract void PlantVegetable(); 9 } 10 }
1 namespace 简单工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 根菜类 5 /// </summary> 6 public class RootVegetable:Vegetable 7 { 8 public override void PlantVegetable() 9 { 10 Console.WriteLine("亲!我在种植大豆,胡萝卜,还有大头菜哦!"); 11 } 12 } 13 }
1 namespace 简单工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 茎菜类 5 /// </summary> 6 public class StemVegetable:Vegetable 7 { 8 public override void PlantVegetable() 9 { 10 Console.WriteLine("亲啊!我在种植竹笋,莲藕,还有马铃薯哦!"); 11 } 12 } 13 }
3).此时如果工人再种植叶莱类植物的话,只需要增加一个继承父类Vegetable的子类来实现,这样的设计满足了类之间的层次关系,每一个类都只负责一件具体的事情。在应用程序中,当工人种植根菜类植物时,代码如下:
namespace 简单工厂模式_RootVegetableAndStemVegetable { public class Program { public static void Main(string[] args) { ///获得茎菜类蔬菜 Vegetable vge = new RootVegetable(); vge.PlantVegetable(); Console.ReadLine(); } } }
如果工人由种植根菜类植物变成种植茎菜类植物或者叶菜类植物,那么在应用程序中,诸多代码就要改变,工作量就会增加,此时就需要解耦具体的种植哪类植物和应用程序。这就要引入简单工厂模式了,代码如下:
1 namespace 简单工厂模式_RootVegetableAndStemVegetable 2 { 3 public class VegetableFactory 4 { 5 public static Vegetable GetVegetableInstance(string vegetable) 6 { 7 Vegetable vge = null; 8 if (vegetable.Equals("根菜类蔬菜")) 9 { 10 return new RootVegetable(); 11 } 12 else if (vegetable.Equals("茎菜类蔬菜")) 13 { 14 return new StemVegetable(); 15 } 16 17 return vge; 18 } 19 } 20 }
此时应用程序代码如下:
1 namespace 简单工厂模式_RootVegetableAndStemVegetable 2 { 3 public class Program 4 { 5 public static void Main(string[] args) 6 { 7 ///获得茎菜类蔬菜 8 Vegetable vge1 = (Vegetable)VegetableFactory.GetVegetableInstance("茎菜类蔬菜"); 9 vge1.PlantVegetable(); 10 ///获得根菜类蔬菜 11 Vegetable vge2 = (Vegetable)VegetableFactory.GetVegetableInstance("根菜类蔬菜"); 12 vge2.PlantVegetable(); 13 Console.ReadLine(); 14 } 15 } 16 }
VegetableFactory解决了客户端直接依赖于具体对象的问题,客户端可以消除直接创建对象的责任,工人只需根据蔬菜的类型,便可进行种植对应的蔬菜。总之,简单工厂模式实现了对责任的分割。
4).该简单工厂模式UML图:
5).缺点:工厂类集中了所有产品创建逻辑,一旦添加新产品就不得不修改工厂逻辑,这样就会造成工厂逻辑过于复杂,并且,它所能创建的类只能是事先考虑到的。对系统的维护和扩展相当不利。
下面就需要工厂模式来解决了。
B.工厂模式
1).由于简单工厂模式系统难以扩展,一旦添加新的蔬菜类型就不得不修改VegetableFactory中的方法,这样就会造成简单工厂的实现逻辑过于复杂,然而工厂模式可以解决简单工厂模式中存在的这个问题。
在 A.简单工厂模式 的 3) 小点中(前面的都相同),如果工人由种植根菜类植物变成种植茎菜类植物或者叶菜类植物,那么在应用程序中,诸多代码就要改变,工作量就会增加,此时就需要解耦具体的种植哪类植物和应用程序。
如果此时引入工厂模式,由于每一种类型的蔬菜就是工厂种植的产品,有两种类型的蔬菜,就需要两个工厂去种植,代码如下:
1 namespace 工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 根菜类 5 /// </summary> 6 public class RootVegetableFactory 7 { 8 public Vegetable GetVegetableInstance() 9 { 10 return new RootVegetable(); 11 } 12 } 13 }
1 namespace 工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 茎菜类 5 /// </summary> public Vegetable GetVegetableInstance()
{
return new StemVegetable();
} 13 }
2).这两个工厂是平级的,在此基础上抽象出一个公共的接口,如图:
代码如下:
1 namespace 工厂模式_RootVegetableAndStemVegetable 2 { 3 public abstract class VegetableFactory 4 { 5 public abstract Vegetable GetVegetableInstance(); 6 } 7 }
1 namespace 工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 根菜类 5 /// </summary> 6 public class RootVegetableFactory:VegetableFactory 7 { 8 public override Vegetable GetVegetableInstance() 9 { 10 return new RootVegetable(); 11 } 12 } 13 }
namespace 工厂模式_RootVegetableAndStemVegetable { /// <summary> /// 茎菜类 /// </summary> public class StemVegetableFactory:VegetableFactory { public override Vegetable GetVegetableInstance() { return new StemVegetable(); } } }
3).工厂模式之所以可以解决简单工厂的模式,是因为它的实现把具体产品的创建推迟到子类中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式就可以允许系统不修改工厂类逻辑的情况下来添加新产品。
如果此时在种植叶菜类蔬菜,只需增加叶菜类蔬菜工厂和叶菜类蔬菜类。而不用像简单工厂模式中那样去修改工厂类中的实现。应用程序代码如下:
1 namespace 工厂模式_RootVegetableAndStemVegetable 2 { 3 public class Program 4 { 5 public static void Main(string[] args) 6 { 7 // 初始化工厂 8 VegetableFactory Factory = new RootVegetableFactory(); 9 //种植根菜类蔬菜 10 Vegetable vge = Factory.GetVegetableInstance(); 11 vge.PlantVegetable(); 12 Console.ReadLine(); 13 } 14 } 15 }
此时如果想种植茎菜类蔬菜,只需更改
VegetableFactory Factory = new StemVegetableFactory();
其余地方不需修改。如果利用.NET中的反射机制来进一步修改我们的程序,这时就要用到配置文件了,这样可以避免上述的修改。配置文件如下:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <startup> 4 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> 5 </startup> 6 <appSettings> 7 <add key="factoryName" value="工厂模式_RootVegetableAndStemVegetable.RootVegetableFactory"/> 8 </appSettings> 9 </configuration>
应用程序如下:
namespace 工厂模式_RootVegetableAndStemVegetable { public class Program { public static void Main(string[] args) { string factoryName = ConfigurationManager.AppSettings["factoryName"]; VegetableFactory vf =(VegetableFactory) Assembly.Load("工厂模式_RootVegetableAndStemVegetable").CreateInstance(factoryName); Vegetable vge = vf.GetVegetableInstance(); vge.PlantVegetable(); Console.ReadLine(); } } }
注意:1.Assembly.Load("XXX")的使用说明如下:XXX并不是命名空间,而是程序集名称,也就是dll的名称,,可以在bin目录下看一下,而不是类名!
即:Assembly.Load("程序集").CreateInstance("命名空间.类")
2.注意CreateInstance()一定是 命名空间.类名,否则创建的实例为空.
4)该工厂模式UML图
5)缺点:在工厂模式中,一个工厂只能创建一种产品,如果要求工厂创建多种产品,工厂模式就不好用了。下面就需要 抽象工厂模式 来解决了。
C.抽象工厂模式
1).随着科技的发展,工人逐步要种植转基因与非转基因食品了,在以前的蔬菜种类上又增加了一个层次,这个时候无法将其作为一个层次来解决,所以必须采用抽象工厂的方式来解决。依然以种植根菜类蔬菜和茎菜类蔬菜为例。
此时在蔬菜下有根菜类蔬菜类型 和 茎菜类蔬菜类型,在根菜类蔬菜类型下 有转基因根菜类蔬菜 和 非转基因食品根菜类蔬菜,在茎菜类蔬菜类型下有 转基因茎菜类蔬菜 和 非转基因茎菜类蔬菜 。如图:
代码如下:
namespace 抽象工厂模式_RootVegetableAndStemVegetable{ /// <summary> /// 蔬菜接口 /// </summary> interface Vegetable { } }
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable
2 { 3 /// <summary> 4 /// 根菜 5 /// </summary> 6 public abstract class RootVegetable:Vegetable 7 { 8 public abstract void PlantRootVegetable(); 9 } 10 }
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 茎菜 5 /// </summary> 6 public abstract class StemVegetable:Vegetable 7 { 8 public abstract void PlantStemVegetable(); 9 } 10 }
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 转基因根菜 5 /// </summary> 6 public class GMFRootVegetable:RootVegetable 7 { 8 public override void PlantRootVegetable() 9 { 10 Console.WriteLine("亲!我在种植转基因类型的大豆,胡萝卜,还有大头菜哦!"); 11 } 12 } 13 }
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 非转基因根菜 5 /// </summary> 6 public class NonGMFRootVegetable:RootVegetable 7 { 8 public override void PlantRootVegetable() 9 { 10 Console.WriteLine("亲!我在种植非转基因类型的大豆,胡萝卜,还有大头菜哦!"); 11 } 12 } 13 }
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 转基因茎菜 5 /// </summary> 6 public class GMFStemVegetable:StemVegetable 7 { 8 public override void PlantStemVegetable() 9 { 10 Console.WriteLine("亲啊!我在种植转基因类型的芹菜,莲藕,还有马铃薯哦!"); 11 } 12 } 13 }
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 非转基因茎菜 5 /// </summary> 6 public class NonGMFStemVegetable:StemVegetable 7 { 8 public override void PlantStemVegetable() 9 { 10 Console.WriteLine("亲啊!我在种植非转基因类型的芹菜,莲藕,还有马铃薯哦!"); 11 } 12 } 13 }
2).由于现在种植转基因与非转基因蔬菜,可以创建 转基因蔬菜工厂 与 非转基因蔬菜工厂,在 转基因蔬菜工厂 下可以种植 转基因根菜类蔬菜 和 转基因茎菜类蔬菜,在 非转基因蔬菜工厂 下可以种植 非转基因根菜类蔬菜 和 非转基因茎菜类蔬菜。
如果现在工人只要求是种植转基因蔬菜,代码如下:
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 转基因工厂 5 /// </summary> 6 public class VegetableFactory { 7 /// <summary> 8 /// 转基因根菜 9 /// </summary> 10 /// <returns></returns> 11 public RootVegetable GetRootVegetableInstance() 12 { 13 return new GMFRootVegetable(); 14 } 15 /// <summary> 16 /// 转基因茎菜 17 /// </summary> 18 /// <returns></returns> 19 public StemVegetable GetStemVegetableInstance() 20 { 21 return new GMFStemVegetable(); 22 } 23 } 24 }
可以很好地解决种植转基因蔬菜的问题,但一段时间后,工人又要种植非转基因蔬菜蔬菜,此时就要修改系统源代码,修改VegetableFactory这个类,代码如下:
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 非转基因工厂 5 /// </summary> 6 public class VegetableFactory: 7 { 8 /// <summary> 9 /// 非转基因根菜 10 /// </summary> 11 /// <returns></returns> 12 public RootVegetable GetRootVegetableInstance() 13 { 14 return new NonGMFRootVegetable(); 15 } 16 /// <summary> 17 /// 非转基因茎菜 18 /// </summary> 19 /// <returns></returns> 20 public StemVegetable GetStemVegetableInstance() 21 { 22 return new NonGMFStemVegetable(); 23 } 24 } 25 }
最终的工作都是对VegetableFactory这个类进行修改。工作量依然没有减少。此时引入 抽象工厂模式,并在 抽象工厂模式 加一个静态方法,便可解决这个问题。如图:
代码如下:
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 抽象工厂 5 /// </summary> 6 public abstract class AbstractFactory 7 { 8 /// <summary> 9 /// 获得根菜类蔬菜 10 /// </summary> 11 public abstract RootVegetable GetRootVegetableInstance(); 12 /// <summary> 13 /// 获得茎菜类蔬菜 14 /// </summary> 15 public abstract StemVegetable GetStemVegetableInstance(); 16 /// <summary> 17 /// 获得转基因工厂还是非转基因工厂 18 /// </summary> 19 public static AbstractFactory GetAbstractFactoryInstance(string factoryName) 20 { 21 AbstractFactory instance = null; 22 if (factoryName.Equals("转基因工厂")) 23 { 24 instance= new GMFVegetableFactory(); 25 } 26 else if (factoryName.Equals("非转基因工厂")) 27 { 28 instance = new NonGMFVegetableFactory(); 29 } 30 31 return instance; 32 } 33 } 34 }
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 转基因工厂 5 /// </summary> 6 public class GMFVegetableFactory:AbstractFactory 7 { 8 /// <summary> 9 /// 转基因根菜 10 /// </summary> 11 /// <returns></returns> 12 public override RootVegetable GetRootVegetableInstance() 13 { 14 return new GMFRootVegetable(); 15 } 16 /// <summary> 17 /// 转基因茎菜 18 /// </summary> 19 /// <returns></returns> 20 public override StemVegetable GetStemVegetableInstance() 21 { 22 return new GMFStemVegetable(); 23 } 24 } 25 }
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 非转基因工厂 5 /// </summary> 6 public class NonGMFVegetableFactory:AbstractFactory 7 { 8 /// <summary> 9 /// 非转基因根菜 10 /// </summary> 11 /// <returns></returns> 12 public override RootVegetable GetRootVegetableInstance() 13 { 14 return new NonGMFRootVegetable(); 15 } 16 /// <summary> 17 /// 非转基因茎菜 18 /// </summary> 19 /// <returns></returns> 20 public override StemVegetable GetStemVegetableInstance() 21 { 22 return new NonGMFStemVegetable(); 23 } 24 } 25 }
应用程序代码:
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 public class Program 4 { 5 public static void Main(string[] args) 6 { 7 AbstractFactory af = AbstractFactory.GetAbstractFactoryInstance("转基因工厂"); 8 ///种植转基因类型蔬菜 9 RootVegetable rootVge = af.GetRootVegetableInstance(); 10 rootVge.PlantRootVegetable(); 11 Console.ReadLine(); 12 } 13 } 14 }
如果想种植 非转基因根菜类蔬菜,只需修改:
1 AbstractFactory af = AbstractFactory.GetAbstractFactoryInstance("非转基因工厂");
不用再担心到底是种植转基因还是非转基因蔬菜,修改的地方非常少。
3).但也有一个小问题,如果有一天,科技已经发展到一定程度,种植需要很长时间,工人直接·采用3D打印技术,打印各种类型的蔬菜,这是在原有的层次上又增加了一个层次,增加一个
3D打印蔬菜工厂到不是难事,但要修改AbstractFactory这个类,在GetAbstractFactoryInstance(string factoryName)方法中添加一个if(){}判断语句,依然要修改源代码。可以利用
.NET中的反射机制来进一步修改我们的程序,这时就要用到配置文件了,这样可以避免上述的修改。配置文件如下:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <startup> 4 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> 5 </startup> 6 <appSettings> 7 <add key="factoryName" value="抽象工厂模式_RootVegetableAndStemVegetable.GMFVegetableFactory"/> 8 </appSettings> 9 </configuration>
此时AbstractFactory类修改如下:
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 /// <summary> 4 /// 抽象工厂 5 /// </summary> 6 public abstract class AbstractFactory 7 { 8 /// <summary> 9 /// 获得根菜类蔬菜 10 /// </summary> 11 public abstract RootVegetable GetRootVegetableInstance(); 12 /// <summary> 13 /// 获得茎菜类蔬菜 14 /// </summary> 15 public abstract StemVegetable GetStemVegetableInstance(); 16 /// <summary> 17 /// 获得转基因工厂还是非转基因工厂 18 /// </summary> 19 public static AbstractFactory GetAbstractFactoryInstance() 20 { 21 string factoryName = ConfigurationSettings.AppSettings["factoryName"]; 22 AbstractFactory instance = null; 23 if (!factoryName.Equals(string.Empty)) 24 { 25 instance = (AbstractFactory)Assembly.Load("抽象工厂模式_RootVegetableAndStemVegetable").CreateInstance(factoryName); 26 } 27 return instance; 28 } 29 } 30 }
应用程序如下:
1 namespace 抽象工厂模式_RootVegetableAndStemVegetable 2 { 3 public class Program 4 { 5 public static void Main(string[] args) 6 { 7 AbstractFactory af = AbstractFactory.GetAbstractFactoryInstance(); 8 ///种植转基因类型蔬菜 9 RootVegetable rootVge = af.GetRootVegetableInstance(); 10 rootVge.PlantRootVegetable(); 11 Console.ReadLine(); 12 } 13 } 14 }
当再增加一个层次时,就不必修改AbstractFactory这个类,只需修改配置文件即可。
4).缺点: 难以支持新种类的产品。难以扩展抽象工厂以生产新种类的产品。这是因为抽象工厂接口确定了可以被创建的产品集合,支持新种类的产品就需要扩展该工厂接口,这将涉及抽象工厂类及其所有子类的改变,这样也就违背了“开发——封闭”原则。
5).该抽象工厂模式的UML图
4.工厂模式VS抽象工厂模式(转载)
1.区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的。
2.工厂方法模式与抽象工厂模式对比:
工厂方法模式 抽象工厂模式
针对的是一个产品等级结构 针对的是面向多个产品等级结构
一个抽象产品类 多个抽象产品类
可以派生出多个具体产品类 每个抽象产品类可以派生出多个具体产品类
一个抽象工厂类,可以派生出多个具体工厂类 一个抽象工厂类,可以派生出多个具体工厂类
每个具体工厂类只能创建一个具体产品类的实例 每个具体工厂类可以创建多个具体产品类的实例