标签:设计模式之简单工厂模式
设计模式之简单工厂模式
动机:
不暴露实例化逻辑来创建对象。通过公共的接口创建新的对象。
这是一个简单的实现,客户端需要一个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