之前讨论了简单工厂模式,回顾一下它的弊端,主要有3个:①当新增一种产品时,需要修改工厂类中的方法,违反了开闭原则。②当产品类非常多的时候,工厂类中的判断逻辑也会变得复杂,不利于维护。③众多客户端都依赖同一个工厂类,当该工厂类无法工作时,调用它的客户端也无法工作。
为了解决上面提到的弊端,我们需要用到工厂方法模式来作为替代方案。工厂方法模式是简单工厂模式的进一步抽象。
工厂方法模式描述
定义
工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。
角色组成
- 1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
- 2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
- 3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
- 4)具体产品角色。
类图构成
工厂方法模式VS简单工厂模式
回到之前的讨论,使用了工厂方法模式之后,当新增一种产品时,我们需要做什么?
- 新增一个产品的实现类ProductC。
- 新增一个具体工厂类。
- 在客户端调用。
如此来看,我们不必修改任何已有的代码,完全符合开闭原则。
工厂方法模式实现代码
产品接口
public interface Product extends Serializable {
void show();
}
产品实现
public class ProductA implements Product {
private static final long serialVersionUID = 1891930199408654755L;
public void show() {
System.out.println("This is A");
}
}
public class ProductB implements Product {
private static final long serialVersionUID = 7748930858331328998L;
public void show() {
System.out.println("This is B");
}
}
工厂接口
public interface Factory {
Product createProduct();
}
工厂实现类
public class ProductAFactory implements Factory {
public Product createProduct() {
return new ProductA();
}
}
public class ProductBFactory implements Factory {
public Product createProduct() {
return new ProductB();
}
}
客户端调用
public class FactoryClient {
public static void main(String[] args) {
Factory factory = new ProductAFactory();
Product product = factory.createProduct();
product.show(); // This is A
factory = new ProductBFactory();
product = factory.createProduct();
product.show(); // This is B
}
}
工厂方法模式存在的弊端
根据上面的逻辑,每新增一种产品,我们就要新增一个产品实现类,新增一个产品工厂实现类。当系统中有数百种产品的话,就要有对应多的工厂类,对于维护是个挑战。
工厂方法模式适用场景
其实也是所有工厂模式的适用场景。
- ①作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
- ②工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。
- ③由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。