标签:设计模式之简单工厂模式
设计模式之简单工厂模式 动机: 不暴露实例化逻辑来创建对象。通过公共的接口创建新的对象。 这是一个简单的实现,客户端需要一个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_RegisteredProducts.put(productID, productClass); } public Product createProduct(String productID) { Class productClass = (Class)m_RegisteredProducts.get(productID); Constructor productConstructor = cClass.getDeclaredConstructor(new Class[] { String.class }); return (Product)productConstructor.newInstance(new Object[] { }); } } 我们可以把registion code注册代码放在任何地方,但是使用static静态代码块在product类里面注册是一个方便的方法,看下面的例子: 1、在product类外面注册: public static void main(String args[]){ Factory.instance().registerProduct("ID1", OneProduct.class); } 2、在product类里面注册: class OneProduct extends Product { static { Factory.instance().registerProduct("ID1",OneProduct.class); } ... } 我们必须确保在factroy使用concrete product具体的product之前完成注册,不然就会出现null point空指针,我们在Main类的static静态代码块中使用Class.forName方法。Class.forName方法支持返回一个类的实例,如果一个编译器没有加载这个类,编译器就会在Class.forName被调用的时候加载。 class Main { static { try { Class.forName("OneProduct"); Class.forName("AnotherProduct"); } catch (ClassNotFoundException any) { any.printStackTrace(); } } 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 { ProductFactory.instance().registerProduct("ID1", new OneProduct()); } public OneProduct createProduct() { return new OneProduct(); } ... } class ProductFactory { public void registerProduct(String productID, Product p) { m_RegisteredProducts.put(productID, p); } public Product createProduct(String productID){ ((Product)m_RegisteredProducts.get(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原理的。
本文出自 “不死的小强” 博客,请务必保留此出处http://qianray.blog.51cto.com/4607992/1878313
标签:设计模式之简单工厂模式
原文地址:http://qianray.blog.51cto.com/4607992/1878313