使用反射在NET中实现动态工厂(第一部分)

原创 2003年05月08日 14:15:00

使用反射在NET中实现动态工厂<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

出处     http://msdn.microsoft.com

    在软件开发进行了若干年后,设计模式逐渐被更多的程序员理解和采用。对常见的特定问题总是有其解决办法,这些解决办法逐渐得到了大家的公认。许多这样的解决办法被汇总整理成设计模式用来解决很多编程中的问题。基于这一点,微软公司提供了一个专栏来讨论各种实用的模式来帮助大家更快的解决开发过程中的问题。

http://msdn.microsoft.com/msdnmag/issues/03/03/designpatterns/default.aspx

在设计模式中经常用的一种叫做:工厂模式。工厂模式的好处是使用动态创建对象(甚至只靠对象的类型来创建对象)来降低对象间的耦合。可是当工厂方法和其他模式一起使用来创建高内聚低耦合的代码的时候,工厂方法并不是值得推荐的。使用.Net的反射机制使用C#语言来创建一个工厂类(没有写最常用的实现的部分)。

关于软件设计中的两大原则:高内聚低耦合的好处我就不多讲了。

工厂设计模式:

举个例子来说明工厂模式的好处:比如A对象需要向B对象发送消息,A必须持有一个B对象的引用来完成这个功能,也就是说:B对象必须经过初始化并且A对象可以访问他。我们大家最长使用的方法就是在A对象中直接初始化B对象,直接持有一个对B对象的引用,这样A对象就必须知道怎样初始化B对象,比如:需要那些初始化的参数等等,有经验的程序员都知道这样编程思路写下的程序的弊端。

怎样解决上面的问题呢。

答案是把创建B对象的工作交给另一个类:C

也就是说:所有需要使用B类的地方统一从C那里后的一个B的实例。

    这就是工厂方法的功能。

    当然,我们不可能完全消除耦和,这种方法是降低了程序的耦合程度,有利于程序以后的修改和扩充。上面采用类C来创建B的方法,还有更好的改进,就是使用接口,也就是我们常说的 :纯虚工厂,那样耦和的程度就更低了。大家可以参考具体的参考资料。

工厂模式中有三个主体需要我们分清: 1、工厂 2、客户  3 产品

客户是:任何需要使用工厂提供对象的对象。

产品是:工厂生成的一个返回到客户的对象。

 

使用工厂模式的一般方法

   工厂模式有很多个版本,不同的做法各有优劣。我们下面比较最常用的两种工厂模式后介绍使用反射机制的工厂模式。

据个例子:

假如你有一个管理电脑零件的程序,其中:

InventoryMgr      是客户,仓库管理员。

PartsFactory      是工厂;

MonitorInvFactory 是显示器工厂;

KeyboardInvFactory 是键盘工厂;

IpartsInventory    是上面的工厂返回的产品。

UML图如下:

 

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />CSDN_Dev_Image_2003-5-41919390.png

下面我把上面的图给大家解释一下:

MainClass 是用来向IventoryMgr来发送一个需要仓库对象请求的类。比如现在我们需要补充仓库的显示器的数量,就可以向IventoryMgr发送这个请求。代码如下:

class MainClass {

    static void <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />Main(string[] args) {

        PartsFactory myfactory = null;

        InventoryMgr myinvmgr = new InventoryMgr();

        foreach(string marg in args){

            switch(marg) {

                case "Monitors":                

                    myfactory = new MonitorInvFactory();

                    break;

                case "Keyboards":

                    myfactory = new KeyboardInvFactory();

                    break;

                default:

                    break;

            }

            if(myfactory != null)

                myinvmgr.ReplenishInventory(myfactory);            

            myfactory = null;

        }

    }

}

    class InventoryMgr {

    public void ReplenishInventory(PartsFactory vfactory) {

        IPartsInventory PartInv = vfactory.ReturnPartInventory();

        PartInv.Restock();

    }

}

 

interface IPartsInventory {

    void Restock();

}

 

class MonitorInventory : IPartsInventory {

    public void Restock() {

        Console.WriteLine("The monitor inventory has been restocked");

    }

} 

 

class KeyboardInventory : IPartsInventory {

    public void Restock() {

        Console.WriteLine("The keyboard inventory has been restocked");

    }

}

   

abstract class PartsFactory {

    public abstract IPartsInventory ReturnPartInventory();

}

 

class MonitorInvFactory : PartsFactory {

    public override IPartsInventory ReturnPartInventory() {

        return (IPartsInventory) new MonitorInventory();

    }     

}

class KeyboardInvFactory : PartsFactory {

    public override IPartsInventory ReturnPartInventory() {

        return (IPartsInventory) new KeyboardInventory();

    }     

}

上面的代码是可以说是一种工厂模式的合理的实现,但是有些不足的地方。

大家可以从耦和的角度看看上面工厂模式的代码实现。一个一个来:

InventoryMgr 没的说,耦合程度很低,他使用接口屏蔽了创建具体的类的信息。即使你增加新的零件(新工厂)也不会影响他。这就是:对扩展开发,对修改关闭的典型例子。同时InventoryMgr 也对实现不同的IpartsInventory 具有低的耦和。

那问题到底在哪里呢?

问题在MainClass中,他违背了“不要和陌生人说话”的公理。

因为MainClass中使用了创建具体类的工厂。从上面的代码可以看出MainClass实际上在参数未传达到之前并不知道具体的工厂,而且他只是简单的创建好类后有给了InventoryMgr 上面的做法实际上把:MainClass MonitorInvFactoryKeyboardInvFactory 等本应该不必要的耦和放到了一起。

一般来讲:一个对象中创建另一个对象的原则是:这个对象需要向其创建的对象发送消息,除非这个对象的任务就是创建和返回其他对象。工厂模式就是这样的一个例子。

MainClass的另一个弊端是他不是高内聚的。

MainClass 不应该考虑到底使用那个具体类来处理请求,他只是派发消息的代理。MainClass的作用只是接受客户消息请求,然后传达给InventoryMgr 做进一步的处理。使用反射机制可以更好的解决这个问题。

我们现在看看工厂方法的另一个常见的做法:

不使用抽象工厂创建对象,而以具体工厂创建对象代之。

这样做代码可以简化不少。

MainClass

InventoryMgr

PartsFactory

有一些变化

IpartsInventory  没有改变

MonitorInvFactory   不再需要

KeyboardInvFactory  不再需要 因为一个具体的工厂代替他们使用了。

最大的变化是使用了一个迭代器:enmInvParts

代码如下:

class MainClass {

    static void Main(string[] args) {       

        InventoryMgr InvMgr = new InventoryMgr();

        foreach(string marg in args){

            switch(marg) {

                case "Monitors":

                    InvMgr.ReplenishInventory(enmInvParts.Monitors);

                    break;

                case "Keyboards":

                    InvMgr.ReplenishInventory(enmInvParts.Keyboards);

                    break;

                default:

                    break;

            }

        }

    }

}

 

public enum enmInvParts : int {Monitors = 1, Keyboards=2}

 

class InventoryMgr {

    public void ReplenishInventory(enmInvParts InventoryPart) {

        PartsFactory factory = new PartsFactory();

        IPartsInventory IP = factory.ReturnPartInventory(InventoryPart);

        IP.Restock();

    }

}

 

class PartsFactory {

    public IPartsInventory ReturnPartInventory(enmInvParts InvPart) {

        IPartsInventory InvType;

 

        switch(InvPart) {

            case enmInvParts.Monitors:

                InvType = new MonitorInventory();       

                break;

            case enmInvParts.Keyboards:

                InvType = new KeyboardInventory();

                break;

            default:

                InvType = null;

                break;

        }

        return InvType;

    }

}

我们现在分析一下上面的代码:

上面提到的MainClass的弊端已经得到了改进。

MainClass不会在和“陌生人说活”了,但是他不得不和工厂耦和。使用enmInvParts 来包装客户端的请求。对客户端请求的包装是合理的,他也简单的把消息给了InventoryMgr

明眼人都能看出来:MainClass的耦和问题转嫁给了PartsFactory。并且PartsFactory IpartsInventory也出现了耦和。

让我们来看看反射机制如何实现低耦和这个崇高的目标吧。

 

Part One

版权声明:本文为博主原创文章,在不删除、修改文章内容的情况下,可以自由转载。

设计模式篇-工厂模式与代理模式的混用(Factory+proxy pattern )

设计模式篇-工厂模式与代理模式的混用(Factory+proxy pattern )本篇博客将介绍一个 工厂模式+ 代理模式 一起混合使用的 demo 此demo的需求 是一个弹弹球工厂, 产品 ...
  • qq_14995933
  • qq_14995933
  • 2016年03月12日 22:42
  • 1168

框架原理反射的应用

企业级开发 企业级应用需要解决:并发,交互,事务,集群,安全,分布式,WEB的一系列问题。 EJB 由EJB(企业级javabean)服务主要提供生命周期管理、代码产生、持续性管理、...
  • Java1029384756
  • Java1029384756
  • 2016年11月15日 21:18
  • 432

java反射在spring中的应用

java反射在spring中的应用
  • bawcwchen
  • bawcwchen
  • 2015年01月18日 22:01
  • 674

Java反射在JVM的实现

转自http://www.jianshu.com/p/f83556bcae59
  • qq_24585769
  • qq_24585769
  • 2017年03月03日 10:19
  • 70

(设计模式)简单工厂模式之通过配置文件动态创建实现类

通常我们在使用简单工厂模式的时候会由创建方法create通过传入的参数来判断要实例化哪个对象,就像下面这样: public static class ImageSelectFactory { ...
  • u011064099
  • u011064099
  • 2015年11月04日 14:44
  • 1579

Java反射在JVM的实现

本文目录 什么是Java反射,有什么用?Java Class文件的结构Java Class加载的过程反射在native的实现附录 1. 什么是Java反射,有什么用? 反射使程序...
  • GarfieldEr007
  • GarfieldEr007
  • 2017年02月24日 23:12
  • 242

Java反射在JVM中的实现

Java反射在JVM中的实现 1什么是反射?反射有什么作用? 2Java Class文件结构介绍 3Java Class文件加载过程 4 反射在native中的应用 什么是反射? 反射使...
  • jim__charles
  • jim__charles
  • 2016年10月14日 13:49
  • 1625

学习笔记----设计模式之动态代理+工厂模式的混合使用简单demo

最近项目有个需求,要用到动态代理调用远程接口,然后就学习了一下该设计模式并记录下来。...
  • li_yan_fei
  • li_yan_fei
  • 2017年04月07日 16:07
  • 480

Java反射在JVM的实现

1. 什么是Java反射,有什么用? 反射使程序代码能够接入装载到JVM中的类的内部信息,允许在编写与执行时,而不是源代码中选定的类协作的代码,是以开发效率换运行效率的一种手段。这使反射成为构建...
  • AlbenXie
  • AlbenXie
  • 2017年04月11日 09:36
  • 158

CocosCreator反射在Android中的使用

CocosCreator反射在Android中的使用 新建一个CocosCreator项目,然后点击构建 构建完成之后,即可用AndroidStudio打开构建的项目 使用Androi...
  • u010596115
  • u010596115
  • 2016年10月23日 19:54
  • 1682
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用反射在NET中实现动态工厂(第一部分)
举报原因:
原因补充:

(最多只允许输入30个字)