我们介绍简单工厂模式,但是简单工厂模式违反了"开-闭"原则,即对"闭"支持不够,即有新产品添加时,需要修改已有的工厂代码。
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。这个核心类则摇身一变,成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触产品类被实例化的细节。类图如下:
从上图中可以看出,设计到的角色如下:
抽象工厂(Creator)角色:该角色是工厂方法模式的核心,它与应用程序无关。
具体工厂(Concrete Creator)角色:该角色实现了抽象工厂接口的具体Java类。具体工厂角色含有与应用密切相关的逻辑,并且受到应用程序的调用以创建产品对象。
抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所声明的接口。工厂方法模式所创建的每一个对象都是某个具体产品角色的实例。
实例:这里依然通过生产小汽车为例子。该实例存需要生产"奔驰"和"宝马"两个品牌的车辆。其中设计的类如下:
Factory:抽象工厂
BenzFactory:奔驰车辆工厂
BmwFactory:宝马车辆工厂
Car:抽象车辆,指定车辆需要的功能接口
BenzCar:奔驰车
BmwCar:宝马车
实例的UML类图如下:
Java实例代码:
// 抽象工厂 public interface Factory { public Car factory(); } // 奔驰具体工厂 public class BenzFactory implements Factory { @Override public Car factory() { return new BenzCar(); } } // 宝马具体工厂 public class BmwFactory implements Factory { @Override public Car factory() { return new BmwCar(); } } // 抽象产品 public interface Car { public void start(); public void stop(); } // 奔驰车具体类 public class BenzCar implements Car { private static final String NAME = BenzCar.class.getSimpleName(); @Override public void start() { System.out.println(NAME + " :: start()"); } @Override public void stop() { System.out.println(NAME + " :: stop()"); } } // 宝马车具体类 public class BmwCar implements Car { private static final String NAME = BmwCar.class.getSimpleName(); @Override public void start() { System.out.println(NAME + " :: start()"); } @Override public void stop() { System.out.println(NAME + " :: stop()"); } } // 客户端 public class Client { public static void main(String[] args) { // 获取奔驰车实例 Factory factory = new BenzFactory(); Car car = factory.factory(); car.start(); car.stop(); // 获取宝马车实例 factory = new BmwFactory(); car = factory.factory(); car.start(); car.stop(); } }
新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可。而简单工厂模式需要修改工厂类的判断逻辑,即工厂方法中的逻辑(if-else或switch)。
每个具体工厂类只负责创建对应的产品。而简单工厂中的工厂类存在复杂的switch逻辑判断。
不使用静态工厂方法,可以形成基于继承的等级结构。简单工厂模式的工厂类使用静态工厂方法。
工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度;
虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
一个具体工厂只能创建一种具体产品;