工厂模式是一种比较常用的设计模式,其基本思想在于使用不同的工厂类型来打造不同产品的部件。例如,我们在打造一间屋子时,可能需要窗户、屋顶、门、房梁、柱子等零部件。有的屋子需要很多根柱子,而有的屋子又不需要窗户。在这样的需求下,就可以使用工厂模式。

(1)工厂模式的传统实现和其弊端

  下图展示了针对屋子设计的传统工厂模式架构图:

上图的设计思路是:

  ①使用者告诉工厂管理者需要哪个产品部件;

  ②工厂管理者分析使用者传入的信息,生成合适的实现工厂接口的类型对象;

  ③通过工厂生产出相应的产品,返回给使用者一个实现了该产品接口的类型对象;

  通过上述思路,实现代码如下:

  ①首先是定义工厂接口,产品接口与产品类型的枚举

IFactory.cs(工厂接口,产品接口一起

  1. /// <summary>
  2. /// 屋子产品的零件
  3. /// </summary>
  4. public enum RoomParts
  5. {
  6. Roof,
  7. Window,
  8. Pillar
  9. }
  10. /// <summary>
  11. /// 工厂接口
  12. /// </summary>
  13. public interface IFactory
  14. {
  15. IProduct Produce();
  16. }
  17. /// <summary>
  18. /// 产品接口
  19. /// </summary>
  20. public interface IProduct
  21. {
  22. string GetName();
  23. }

②其次是具体实现产品接口的产品类:窗户、屋顶和柱子

Product.cs

  1. /// <summary>
  2. /// 屋顶
  3. /// </summary>
  4. public class Roof : IProduct
  5. {
  6. // 实现接口,返回产品名字
  7. public string GetName()
  8. {
  9. return "屋顶";
  10. }
  11. }
  12. /// <summary>
  13. /// 窗户
  14. /// </summary>
  15. public class Window : IProduct
  16. {
  17. // 实现接口,返回产品名字
  18. public string GetName()
  19. {
  20. return "窗户";
  21. }
  22. }
  23. /// <summary>
  24. /// 柱子
  25. /// </summary>
  26. public class Pillar : IProduct
  27. {
  28. // 实现接口,返回产品名字
  29. public string GetName()
  30. {
  31. return "柱子";
  32. }
  33. }

③然后是具体实现工厂接口的工厂类:实现接口返回一个具体的产品对象

Factory.cs

  1. /// <summary>
  2. /// 屋顶工厂
  3. /// </summary>
  4. public class RoofFactory : IFactory
  5. {
  6. // 实现接口,返回一个产品对象
  7. public IProduct Produce()
  8. {
  9. return new Roof();
  10. }
  11. }
  12. /// <summary>
  13. /// 窗户工厂
  14. /// </summary>
  15. public class WindowFactory : IFactory
  16. {
  17. // 实现接口,返回一个产品对象
  18. public IProduct Produce()
  19. {
  20. return new Window();
  21. }
  22. }
  23. /// <summary>
  24. /// 柱子工厂
  25. /// </summary>
  26. public class PillarFactory : IFactory
  27. {
  28. // 实现接口,返回一个产品对象
  29. public IProduct Produce()
  30. {
  31. return new Pillar();
  32. }
  33. }

 ④最后是工厂管理类:组织起众多的产品与工厂

FactoryManager.cs

  1. class FactoryManager
  2. {
  3. public static IProduct GetProduct(RoomParts part)
  4. {
  5. IFactory factory = null;
  6. //传统工厂模式的弊端,工厂管理类和工厂类的紧耦合
  7. switch (part)
  8. {
  9. case RoomParts.Roof:
  10. factory = new RoofFactory();
  11. break;
  12. case RoomParts.Window:
  13. factory = new WindowFactory();
  14. break;
  15. case RoomParts.Pillar:
  16. factory = new PillarFactory();
  17. break;
  18. default:
  19. return null;
  20. }
  21. IProduct product = factory.Produce();
  22. Console.WriteLine("生产了一个产品:{0}", product.GetName());
  23. return product;
  24. }
  25. }

按照国际惯例,我们实现一个入口方法来测试一下:

Client.cs

  1. class Client
  2. {
  3. static void Main(string[] args)
  4. {
  5. IProduct window = FactoryManager.GetProduct(RoomParts.Window);
  6. Console.WriteLine("我获取到了{0}", window.GetName());
  7. IProduct roof = FactoryManager.GetProduct(RoomParts.Roof);
  8. Console.WriteLine("我获取到了{0}", roof.GetName());
  9. IProduct pillar = FactoryManager.GetProduct(RoomParts.Pillar);
  10. Console.WriteLine("我获取到了{0}", pillar.GetName());
  11. Console.ReadKey();
  12. }
  13. }

 当一个新的产品—地板需要被添加时,我们需要改的地方是:添加零件枚举记录、添加针对地板的工厂类、添加新地板产品类,修改工厂管理类(在switch中添加一条case语句),这样设计的优点在于无论添加何种零件,产品使用者都不需要关心内部的变动,可以一如既往地使用工厂管理类来得到希望的零件,而缺点也有以下几点:

  ①工厂管理类和工厂类族耦合;

  ②每次添加新的零件都需要添加一对工厂类和产品类,类型会越来越多;

  

(2)基于反射的工厂模式的实现

  利用反射机制可以实现更加灵活的工厂模式,这一点体现在利用反射可以动态地获知一个产品由哪些零部件组成,而不再需要用一个switch语句来逐一地寻找合适的工厂。

①产品、枚举和以上一致,这里的改变主要在于添加了两个自定义的特性,这两个特性会被分别附加在产品类型和产品接口上:

ProductAttribute.cs

  1. /// <summary>
  2. /// 该特性用于附加在产品类型之上
  3. /// </summary>
  4. [AttributeUsage(AttributeTargets.Class)]
  5. public class ProductAttribute : Attribute
  6. {
  7. // 标注零件的成员
  8. private RoomParts myRoomPart;
  9. public ProductAttribute(RoomParts part)
  10. {
  11. myRoomPart = part;
  12. }
  13. public RoomParts RoomPart
  14. {
  15. get
  16. {
  17. return myRoomPart;
  18. }
  19. }
  20. }
  21. /// <summary>
  22. /// 该特性用于附加在产品接口类型之上
  23. /// </summary>
  24. [AttributeUsage(AttributeTargets.Interface)]
  25. public class ProductListAttribute : Attribute
  26. {
  27. // 产品类型集合
  28. private Type[] myList;
  29. public ProductListAttribute(Type[] products)
  30. {
  31. myList = products;
  32. }
  33. public Type[] ProductList
  34. {
  35. get
  36. {
  37. return myList;
  38. }
  39. }
  40. }

②下面是产品接口和产品类族的定义,其中产品接口使用了 ProductListAttribute 特性,而每个产品都使用了 ProductAttribute 特性:

  1. /// <summary>
  2. /// 屋顶
  3. /// </summary>
  4. [Product(RoomParts.Roof)]
  5. public class Roof : IProduct
  6. {
  7. // 实现接口,返回产品名字
  8. public string GetName()
  9. {
  10. return "小天鹅屋顶";
  11. }
  12. }
  13. /// <summary>
  14. /// 窗户
  15. /// </summary>
  16. [Product(RoomParts.Window)]
  17. public class Window : IProduct
  18. {
  19. // 实现接口,返回产品名字
  20. public string GetName()
  21. {
  22. return "双汇窗户";
  23. }
  24. }
  25. /// <summary>
  26. /// 柱子
  27. /// </summary>
  28. [Product(RoomParts.Pillar)]
  29. public class Pillar : IProduct
  30. {
  31. // 实现接口,返回产品名字
  32. public string GetName()
  33. {
  34. return "小米柱子";
  35. }
  36. }

③下面是修改后的工厂类,由于使用了反射特性,这里一个工厂类型就可以生产所有的产品:

Factory.cs

  1. public class Factory
  2. {
  3. public IProduct Product(RoomParts parts)
  4. {
  5. ProductListAttribute attr =
  6. (ProductListAttribute)System.Attribute.GetCustomAttribute(typeof(IProduct), typeof(ProductListAttribute));
  7. foreach (var type in attr.ProductList)
  8. {
  9. ProductAttribute pa =
  10. (ProductAttribute)System.Attribute.GetCustomAttribute(type, typeof(ProductAttribute));
  11. if (pa.RoomPart == parts)
  12. {
  13. object product = Assembly.GetExecutingAssembly().CreateInstance(type.FullName);
  14. return product as IProduct;
  15. }
  16. }
  17. return null;
  18. }
  19. }
  20. ///// <summary>
  21. ///// 屋顶工厂
  22. ///// </summary>
  23. //public class RoofFactory : IFactory
  24. //{
  25. //    // 实现接口,返回一个产品对象
  26. //    public IProduct Produce()
  27. //    {
  28. //        return new Roof();
  29. //    }
  30. //}
  31. ... ...

④最后时修改后的工厂管理类,核心只有三行代码:

FactoryManager.cs

  1. class FactoryManager
  2. {
  3. public static IProduct GetProduct(RoomParts part)
  4. {
  5. //IFactory factory = null;
  6. ////传统工厂模式的弊端,工厂管理类和工厂类的紧耦合
  7. //switch (part)
  8. //{
  9. //        case RoomParts.Roof:
  10. //        factory = new RoofFactory();
  11. //        break;
  12. //    case RoomParts.Window:
  13. //        factory = new WindowFactory();
  14. //        break;
  15. //        case RoomParts.Pillar:
  16. //       factory = new PillarFactory();
  17. //        break;
  18. //    default:
  19. //        return null;
  20. //}
  21. //IProduct product = factory.Produce();
  22. Factory factory = new Factory();
  23. IProduct product = factory.Product(part);
  24. Console.WriteLine("生产了一个产品:{0}", product.GetName());
  25. return product;
  26. }
  27. }

上述代码中最主要的变化在于两点:
其一是工厂管理类不再需要根据不同的零件寻找不同的工厂,因为只有一个工厂负责处理所有的产品零件;
其二是产品类型和产品接口应用了两个自定义特性,来方便工厂进行反射。
 ProductAttribute 附加在产品类上,标注了当前类型代表了哪个产品零件。而 ProductListAttribute 则附加在产品接口之上,方便反射得知一共有多少产品零件。
这时需要添加一个新的地板产品零件类型时,我们需要做的是:
1.添加零件枚举记录
  1. /// <summary>
  2. /// 屋子产品的零件
  3. /// </summary>
  4. public enum RoomParts
  5. {
  6. Roof,
  7. Window,
  8. Pillar,
  9. Floor //地板
  10. }
2.添加代表地板的类型(Product.cs)
  1. /// <summary>
  2. /// 地板
  3. /// </summary>
  4. [Product(RoomParts.Floor)]
  5. public class Floor : IProduct
  6. {
  7. // 实现接口,返回产品名字
  8. public string GetName()
  9. {
  10. return "地板";
  11. }
  12. }
3.修改添加在IProduct上的属性初始化参数(增加地板类型),
  1. /// <summary>
  2. /// 产品接口
  3. /// </summary>
  4. [ProductList(new Type[] { typeof(Roof), typeof(Window), typeof(Pillar), typeof(Floor) })]
  5. public interface IProduct
  6. {
  7. string GetName();
  8. }
可以看到这时调用者、工厂管理类和工厂都不再需要对新添加的零件进行改动,程序只需要添加必要的类型和枚举记录即可。当然,这样的设计也存在一定缺陷:反射的运行效率相对较低,在产品零件相对较多时,每生产一个产品就需要反射遍历这是一件相当耗时的工作。

作者:周旭龙

出处:http://www.cnblogs.com/edisonchou/p/4827578.html

 

C#回顾 - 7.如何使用反射实现工厂模式?的更多相关文章

  1. java反射机制(工厂模式)

    http://www.phpddt.com/dhtml/338.html java里面没有typeof,js有. 我终于实现了用反射机制编写的工厂模式.java反射在工厂模式可以体现. 包含产品接口类 ...

  2. IOC的实现原理—反射与工厂模式的结合

    反射机制概念   我们考虑一个场景,如果我们在程序运行时,一个对象想要检视自己所拥有的成员属性,该如何操作?再考虑另一个场景,如果我们想要在运行期获得某个类的Class信息如它的属性.构造方法.一般方 ...

  3. java学习笔记之反射—反射和工厂模式

    简单工厂模式又称为静态工厂方法模式,它是由工厂对象来决定要创建哪一种类的实例化对象. 静态工厂代码: class Factory{ private Factory() {} public static ...

  4. Java反射+简单工厂模式总结

    除了 new 之外的创建对象的方法 通过 new 创建对象,会使得程序面向实现编程,先举个例子,某个果园里现在有两种水果,一种是苹果,一种是香蕉,有客户想采摘园子里的水果,要求用get()方法表示即可 ...

  5. C# 反射+抽象工厂模式

    此模式可以很好的更换程序使用不同的数据库 1.用到的属性类 using System; using System.Collections.Generic; using System.Linq; usi ...

  6. java 反射的应用 以及通过反射 用到的工厂模式

    java反射详解 本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案 ...

  7. Java反射机制在工厂模式中的应用

    在本篇文章中就不详细介绍工厂模式,主要介绍一下反射在工厂模式中的使用,让读者对反射机制带来的好处有更深的认识. 首先看一下简单工厂模式 简单工厂模式(simple factory)是类的创建模式,又叫 ...

  8. 反射 + 抽象工厂模式切换DB数据源(附Demo)

    首先,设计模式的文章源自于程杰的<大话设计模式>这本书,这本书个人感觉很适合我,看着不累,能够安安心心的阅读学习.在这里十分感谢程杰的这本书,我博文中的例子会根据书上的例子来.为了不侵犯这 ...

  9. java 设计模式之工厂模式与反射的结合

    工厂模式: /**  * @author Rollen-Holt 设计模式之 工厂模式  */   interface fruit{     public abstract void eat(); } ...

随机推荐

  1. Fiddler 抓包工具总结

    阅读目录 1. Fiddler 抓包简介 1). 字段说明 2). Statistics 请求的性能数据分析 3). Inspectors 查看数据内容 4). AutoResponder 允许拦截制 ...

  2. 一些js 插件的作用

    前言: 从一些开源网站上下载下来的 后台管理系统模板一般会有很多的js ,其js 的功能是什么呢?这里随手查询了一下,记录下来 正文: 1.zDialog.js 各种弹窗插件详细案例:http://w ...

  3. UIDynamic - 推动行为: UIPushBehavior

    用途: 从一个点移动到另外一个点; 相关属性: mode : UIPushBehaviorModeContinuous  //推移模式 angle : setAngle  //推移角度 magnitu ...

  4. css 拾遗

    1, 实现尖角 <style> .up{ border-top: 30px solid red; border-right:30px solid gold; border-bottom:3 ...

  5. Nginx基本使用

    Nginx基本使用 下载源码包http://nginx.org/ http://nginx.org/en/download.html yum -y install pcre-devel openssl ...

  6. 没有为 COM 互操作注册程序集 请使用 regasm.exe /tlb 注册该程序集——解决办法

    错误现象: 错误 6 没有为 COM 互操作注册程序集“DevExpress.Utils.v13.1, Version=13.1.7.0, Culture=neutral, PublicKeyToke ...

  7. C#中的多态性

    1.重载(overload) public void Sleep() { Console.WriteLine("Animal睡觉"); } public int Sleep(int ...

  8. Acer-宏碁电脑BOIS

    进入电脑BOIS界面; 1.开机(一闪而过)注意第一屏左下角,会有进入BIOS按键提示. 2.如一开机没有进入BIOS的键值提示,取而代之的是品牌机的Logo,可参阅以下列表:不是品牌机可参阅主板设置 ...

  9. C#使用 DirectX SDK 9做视频播放器 并在视频画线添加文字 VMR9

    视频图像处理系列 索引 VS2013下测试通过. 在百度中搜索关键字“DirectX SDk”,或者进入微软官网https://www.microsoft.com/en-us/download/det ...

  10. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【开篇】【持续更新中。。。】

    最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tuto ...