设计模式之简单工厂模式

来源:互联网 发布:匡恩网络武汉 编辑:程序博客网 时间:2024/05/18 20:07
设计模式之简单工厂模式动机:        不暴露实例化逻辑来创建对象。通过公共的接口创建新的对象。        这是一个简单的实现,客户端需要一个product,但是client不直接使用new对象,而是通过提供需要的对象信息来找factory得到新的product。        这个factory实例化一个具体的product并返回(转化成抽象的类),client段使用这个抽象的类而不用考虑它具体的实现。应用举例:        也许工厂模式是使用最多的模式之一。举个例子,一个操作图像的图形应用。在我们实现绘画的模块就是client,而那些shapes图形就是products,所有的图形都继承自一个abstract shape抽象的形状类(或者接口)。 这个abstract shape定义了绘画draw和move方法去让子类实现。让我们假设有个创建圆形的命令,client接收一个string类型的图形类型参数,client从factory得到concrete shape转换成abstract shape。        这样的好处是很显然的:新增一个图形不用修改client的代码,只要在factory的实现里面增加新的类型即可。详细问题和解决方法:        新手使用switch/case参数化factory,生成product的方法可以被重写,所以factory可以生成更多类型的product对象,使用一个条件(输入一个方法参数或者一些全局配置参数)头标识哪种product对象应该被创建。代码如下:public class ProductFactory{    public Product createProduct(String ProductID){        if (id==ID1)            return new OneProduct();        if (id==ID2) return            return new AnotherProduct();        ... // so on for the other Ids        return null; //if the id doesn't have any of the expected values    }    ...}        这种实现方法是简单直接的(让我们称之为新手实现),这里的问题就是,新增一种product我们就要修改factory类,不够弹性,违反了开闭原则。当然我们可以继承factory类,但是别忘了factory类通常是单例的。注册类-使用反射reflection:        如果你可以使用反射,就可以在不修改factory的前提下注册新的product类。在不知道product类型的前提下我们在facoty中创建product对象,我们可使用map保存productID和product type,在这种情况下,新增一个新的product,需要在map中注册该product,这个操作不需要修改factory的代码:class ProductFactory{    private HashMap m_RegisteredProducts = new HashMap();    public void registerProduct (String productID, Class productClass)    {        m_(productID, productClass);    }    public Product createProduct(String productID)    {        Class productClass = (Class)m_(productID);        Constructor productConstructor = (new Class[] {  });        return (Product)(new Object[] { });    }}        我们可以把registion code注册代码放在任何地方,但是使用static静态代码块在product类里面注册是一个方便的方法,看下面的例子:1、在product类外面注册:public static void main(String args[]){        ().registerProduct("ID1", );    } 2、在product类里面注册:class OneProduct extends Product{static {().registerProduct("ID1",);}...}        我们必须确保在factroy使用concrete product具体的product之前完成注册,不然就会出现null point空指针,我们在Main类的static静态代码块中使用方法。方法支持返回一个类的实例,如果一个编译器没有加载这个类,编译器就会在被调用的时候加载。class Main{    static    {        try        {            ("OneProduct");            ("AnotherProduct");        }        catch (ClassNotFoundException any)        {            ();        }    }    public static void main(String args[]) throws PhoneCallNotRegisteredException    {        ...    }}        这种反射实现有它的坏处,一个主要的坏处就是它的性能表现,使用反射要比不使用反射性能表现降低10%。注册类-不使用反射:        在之前的段落中我们看到facotory使用map保存productID和product type,这个注册器在factory外面实现,因为通过使用反射不用再关心所要创建对象的类型。        我们不想使用反射,但是同时factory又不需要考虑product类型。我们在product abstract class里面新增一个新的abstract方法,每个具体的类都要实现设个方法去创造自己。我们也不得不改变注册器这样我们将注册具体的product对象。abstract class Product{    public abstract Product createProduct();    ...}class OneProduct extends Product{    ...    static    {        ().registerProduct("ID1", new OneProduct());    }    public OneProduct createProduct()    {        return new OneProduct();    }    ...}class ProductFactory{    public void registerProduct(String productID, Product p)    {        m_(productID, p);    }    public Product createProduct(String productID){        ((Product)m_(productID)).createProduct();    }}一个更高级的解决方法-使用抽象工厂abstract factory(工厂方法 factory method):    这种实现代表一个可修改的注册器类实现,假设我们新增一个新的product,使用过程化的switch/case我们需要修改factory类的代码,而使用注册器类,我们要做的只是把注册器类给factory,而不用修改factory,这肯定是一个弹性的解决方式。    过程化的实现方式是典型的违背开闭原则的坏例子,我们能看到有很多扩展factory的直接解决方法去避免修改factory。工厂方法模式factory method pattern经典的实现方式有一些坏处通过注册器,而没有很多的好处: 好处:当product对象被创建的时候,继承的factory method可以被修改去表现添加的操作。坏处:    1、factory必须要用singleton实现。    2、每个factory必须要在使用前先实例化。    3、实现起来有更多的困难。    4、如果一个新的product要被创建,一个新的factory要被创建。不管怎么样,经典的实现方式有它的好处,可以帮助我们理解抽象工厂模式abstract factory pattern。结论:        当你设计一个应用的时候,考虑你是否需要使用factory,也许使用factory会带来没必要的复杂。如果你有很多类有相同的基本类型,你就需要使用factory,如果你有许多如下的代码,你就要重新考虑:(if (ConcreteProduct)genericProduct typeof )    ((ConcreteProduct)genericProduct).doSomeConcreteOperation().        如果你决定使用factory模式,我会推荐你使用带注册器的实现(使用反射或者不使用反射都行),避免使用factory method,记住switch/case是最简单,违反开闭原则,只是用来解释factory原理的。


0 0
原创粉丝点击