设计模式系列-工厂方法模式
回顾下设计模式系列《工厂模式》那片文章,里面描述了如何利用工厂模式来模拟一个换灯泡的场景,该场景中模拟了:普通灯泡、节能灯泡、彩色灯泡。它们统一由一个工厂(工厂类)来创造,我们需要使用哪种灯泡时,只需通知工厂类给我们打造一个相同的灯泡即可,类图如下:
创新互联自2013年创立以来,是专业互联网技术服务公司,拥有项目网站建设、做网站网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元苏家屯做网站,已为上家服务,为苏家屯各地企业和个人服务,联系电话:18980820575
由上面边的类图可见,所有类型的灯泡都由灯泡工厂来创建,那这个时候,制造灯泡的工厂因为企业扩大了,需要增加产量,那么此时一个工厂肯定是应付不过来了,而且当前一个工厂所造的灯泡种类也多,更加加大了工厂的制造压力,此时,企业扩建的最好办法就是,增加工厂,各自工厂都只专注于一种灯泡的制造。
1.工厂方法模式
首先我们来看看什么是工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
工厂方法模式类图如下:
Product:定义工厂方法所创建的对象的接口。相当于上边场景中的灯泡抽象。
ConcreteProduct:具体实现Product抽象的具体产品类。相当于上边场景中的具体灯泡。
Creator:声明工厂方法,该方法返回一个Product类型的对象。
ConcreteCreator:重定义工厂方法返回一个ConcreteProduct实例。
可能这会大家看完这个类图会有点模糊,不过没关系,接下来我们利用工厂方法模式来实现我们上边的场景(企业扩大需要建立更多的工厂)。
首先,企业扩大了,需要增加产量建立更多的工厂来创建,为了更好的提高生产效率,每个工厂只专注于生产一种种类的灯泡,利用工厂方法模式设计的类图如下:
边分析边实现代码:
第一步,工厂扩大了,所造的产品还是灯泡,所以我们还是要把灯泡先抽象出来,为何要抽象请参考《工厂模式》这篇文章。
- //灯泡的约定
- public interface IBulb
- {
- //统一的发光接口
- public void Luminescence();
- }
第二步,还是实现目前所有种类的具体灯泡类型。代码如下:
- //灯泡
- public class Bulb : IBulb//实现了灯泡的约定、标准 {
- //发光
- public void Luminescence()
- {
- //灯泡发光的实现
- }
- }
- //节能灯泡
- public class FrugalBulb : IBulb //实现了灯泡的约定、标准
- {
- //节能发光
- public void Luminescence()
- {
- //节能灯泡发光的实现
- }
- }
- //彩色灯泡
- public class ColorBulb : IBulb
- {
- //彩色发光
- public void Luminescence()
- {
- //彩色灯泡发光的实现
- }
- }
- //工厂的抽象
- public interface IMyBulbFactory
- {
- IBulb GetBulb();//将来每个工厂都有制造灯泡的行为
- }
第四步,实现制造每个种类灯泡的具体工厂,每个工厂都只制造自己所造种类的灯泡,代码如下:
- //制造普通灯泡的工厂
- public class BulbFactory : IMyBulbFactory
- {
- //该工厂制造灯泡的行为 只能制造普通灯泡
- public IBulb GetBulb()
- {
- return new Bulb();
- }
- }
- //制造节能灯泡的工厂
- public class FrugalBulbFactroy : IMyBulbFactory
- {
- //该工厂制造灯泡的行为 只能制造节能灯泡
- public IBulb GetBulb()
- {
- return new FrugalBulb();
- }
- }
- //制造节能灯泡的工厂
- public class ColorBulbFactroy : IMyBulbFactory
- {
- //该工厂制造灯泡的行为 只能制造彩色灯泡
- public IBulb GetBulb()
- {
- return new ColorBulb();
- }
- }
- static void Main(string[] args)
- {
- //需要普通灯泡
- IMyBulbFactory bulbFactory = new BulbFactory();
- IBulb bulb = bulbFactory.GetBulb();
- bulb.Luminescence(); //普通灯泡发光
- //需要节能灯泡
- IMyBulbFactory frugalBulbFactroy = new FrugalBulbFactroy();
- IBulb frugalBulb = frugalBulbFactroy.GetBulb();
- frugalBulb.Luminescence(); //节能灯泡发光
- //需要彩色灯泡
- IMyBulbFactory colorbulbFacroty = new ColorBulbFactroy();
- IBulb colorBulb = colorbulbFacroty.GetBulb();
- colorBulb.Luminescence(); //彩色灯泡发光
- }
2.使用反射的工厂方法模式
那么如何接触上边的耦合度呢?可以通过C#的反射机制,将当前所有工厂都配置到配置文件中,然后在配置一个当前需要使用的工厂节点,配置文件如下:
这是我们还需要封装一个专门提供具体工厂的类,为了方便这个类我就不考虑耦合了度。代码如下:
- //用来提供当前需要使用的工厂 当前使用的工厂在配置文件中nonfactoty节点中配置
- public class FactroyProvider
- {
- public static IMyBulbFactory WhereToFactroy()
- {
- string fName = string.Empty;
- string factoryName = string.Empty;
- IMyBulbFactory factory = null;
- if(!string.IsNullOrEmpty(ConfigurationManager.AppSettings["NonFactory"]))
- {
- factoryName = ConfigurationManager.AppSettings["NonFactory"];
- if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings[factoryName]))
- {
- fName = ConfigurationManager.AppSettings[factoryName];
- factory = Assembly.Load("设计模式系列").CreateInstance(fName) as IMyBulbFactory;
- }
- }
- return factory;
- }
- }
3.工厂方法模式与工厂模式的区别
说道这里,不知道大家会不会有一个疑问,总之刚开始我是有这个疑问,疑问就是它和工厂模式的区别是什么呢?
首先我们回顾下《工厂模式》中的工厂类的代码,代码如下:
- public class MyBulbFactory
- {
- public static IBulb GetBulb(string bulbName)
- {
- IBulb bulb = null;
- //告诉我你要什么灯泡,我制造相应的灯泡给你
- switch (bulbName)
- {
- case "bulb":
- bulb = new Bulb();
- break;
- case "frugalbulb":
- bulb = new FrugalBulb();
- break;
- case "colorbulb":
- bulb = new ColorBulb();
- break;
- }
- return bulb;
- }
- }
- //需要普通灯泡
- IMyBulbFactory bulbFactory = new BulbFactory();//这里就制定了具体的工厂类
- IBulb bulb = bulbFactory.GetBulb();
- bulb.Luminescence(); //普通灯泡发光
这样就增加了耦合性。我们在上面使用了反射类解除了耦合,但是又一个疑问出来啦,那么简单工厂模式在创建产品类的时候,如果也使用反射的话那么将来在新增产品的时候也就不需要修改工厂类的代码了,也就是说简单工厂模式使用反射一样可以完美的解决开放封闭原则的问题!
那么新的问题又出来了,那简单工厂模式还有什么作用呢?
我个人有两种理解的方式,仅代表个人观点,也希望大家都详细的说说自己的观点,不要一句话概括噢~!
第一种、在早期设计模式应用的时候,编程语言还没有使用反射的机制时,使用工厂方法模式来升级简单工厂模式,使能够支持开放封闭原则。
第二种、在特殊场景中,工厂方法模式能更好的实现逻辑的组织,例如本篇文章所使用的场景。
分享标题:设计模式系列-工厂方法模式
文章起源:http://ybzwz.com/article/pdgcsg.html