定义
工厂方法模式(Factory Method Pattern)又叫虚拟构造函数(Virtual Constructor)模式或者多态性工厂(Ploymorphic Factory)模式。工厂方法模式定义一个创建产品对象的工厂接口,将实际创建性工作推迟到了子类中。
工厂模式的英文原话是:Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.
意思是:定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。
工厂模式分类
工厂模式可以分为简单工厂、工厂方法和抽象工厂模式。
简单工厂模式
简单工厂模式中,一个工厂类处于对产品实例化的中心位置,它知道每一个产品,它决定哪一个产品类应当被实例化。这个模式的优点是允许客户端相对独立于产品的创建过程,并且在系统引入新产品的时候无需修改客户端,即在某种程度上支持“开-闭”原则。这个模式的缺点是它对“开-闭”原则的支持力度不够,一旦有新的产品加入到系统中,则需要修改工厂类,将必要的逻辑加入到工厂类中。
简单工厂模式包含如下角色:
Factory:工厂角色
Product:抽象产品角色
ConcreteProduct:具体产品角色
工厂方法模式
工厂方法模式是简单工厂模式的进一步抽象和推广。由于工厂方法模式具有多态性,工厂方法模式既保持了简单工厂模式的优点,同时又克服了它的缺点。首先,在工厂方法模式中,核心的工厂类不在负责所有的产品的创建,而是将具体创建的工作交给子类去做。这个核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪个产品类应当被实例化的细节。此种进一步抽象化的结果,使这种工厂方法模式可以允许系统在不修改具体工厂角色的情况下引进新的产品,这一特点使得工厂方法模式相比于简单工厂更具有优越性。
工厂方法模式包含如下角色:
Product:抽象产品
ConcreteProduct:具体产品
Factory:抽象工厂
ConcreteFactory:具体工厂
实例
抽象工厂模式
抽象工厂模式是所有形态的工厂模式中最为抽象和最具有一般性的一种形态。抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品的等级结构。
抽象工厂模式包含如下角色:
AbstractFactory:抽象工厂
ConcreteFactory:具体工厂
AbstractProduct:抽象产品
Product:具体产品
工厂方法模式组成
抽象工厂(Creator)角色:该角色是工厂方法模式的核心,与应用系统无关,任何在创建对象的工厂类必须实现这个接口。
具体工厂(Concrete Creater)角色:该角色实现了抽象工厂接口,含有与应用密切相关的逻辑,并且通过调用应用程序来创建产品对象。
抽象产品(Product)角色:该角色负责定义产品的共性,实现对产品最抽象的定义。
具体产品(Concrete Product)角色:该角色实现抽象产品角色所声明的接口,工厂方法模式所创建的每一个对象都是某个具体产品角色的实例。
/** * 工厂方法模式-抽象工厂角色接口 */ public interface Creator { /** * 创建一个产品对象,输入参数类型(特定接口的子类)可以自行设置 */ public <T extends Product>T factory(Class<T> c); //只能创建实现Product接口的类的对象 } /** * 具体工厂角色接口 */ public class ConcreteCreator implements Creator { @Override public <T extends Product> T factory(Class<T> c) { Product product = null; try { product = (Product) Class.forName(c.getName()).newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } return (T)product; } } /** * 抽象产品角色接口 */ public interface Product { //产品类的公共方法 public void method1(); public void method2(); } /** * 具体产品角色接口 */ public class ConcreteProduct implements Product { @Override public void method1() { System.out.println("this is methodone by class"+this.getClass().getName()); } @Override public void method2() { System.out.println("this is methodtwo by class"+this.getClass().getName()); } }
工厂方法模式的优点
1.良好的封装性,代码结构清晰。创建一个对象是有约束条件的,如果一个调用者需要使用一个具体的产品对象,只要知道这个产品对象的类名或约束字符串即可,不用知道创建对象的过程如何,这就降低了模块间的耦合。
2.优秀的可扩展性。在需要增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以适应变化。
3.屏蔽产品类。产品类的实现如何变化,调用者不需要关心,而只需要关心产品的接口,只要接口保持不变,系统的上层模块就不需要发生变化。因为产品的实例化是由工厂类负责的,具体生产何种产品的对象是由不同的工厂类决定的。
4.工厂方法模式是典型的解耦框架。高层模块只需要知道产品类的抽象类,其他的实现类都不用关心。工厂方法模式符合迪米特法则,也符合依赖倒置原则,只依赖产品类的抽象;另外还符合里氏替换原则,可以使用产品子类替换产品父类。
工厂方法的使用场景
1.工厂方法模式是创建一个对象的替代品,因此在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否需要增加一个工厂类进行管理,增加代码的复杂度。
2.需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。
3.工厂方法模式可以用在异构项目中。(例如webservice与一个非java的项目交互)
4.工厂方法模式可以在测试驱动开发的框架下使用。
工厂模式可以与其他模式混合使用(如模板方法模式、单例模式、原型模式等),从而构造出扩展性更好的设计。