Skip to main content

Factory Method 工厂方法

Intent

Factory Method is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. 工厂方法模式是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。

Problem

Imagine that you’re creating a logistics management application. The first version of your app can only handle transportation by trucks, so the bulk of your code lives inside the Truck class. 假设正在开发一款物流运输 app。最初版本只能处理卡车运输

After a while, your app becomes pretty popular. Each day you receive dozens of requests from sea transportation companies to incorporate sea logistics into the app. 此时希望支持海运功能

这可是个好消息。 但是代码问题该如何处理呢? 目前, 大部分代码都与 Trunk class 相关。 在程序中添加 Ships class 需要修改全部代码。 更糟糕的是, 如果你以后需要在程序中支持另外一种运输方式, 很可能需要再次对这些代码进行大幅修改。

Solution

The Factory Method pattern suggests that you replace direct object construction calls (using the new operator) with calls to a special factory method. Don’t worry: the objects are still created via the new operator, but it’s being called from within the factory method. Objects returned by a factory method are often referred to as products.

now you can override the factory method in a subclass and change the class of products being created by the method. 现在可以在子类中重写工厂方法,从而改变其创建产品的类型

There’s a slight limitation though: subclasses may return different types of products only if these products have a common base class or interface. Also, the factory method in the base class should have its return type declared as this interface. 仅当这些产品具有共同的基类或者接口时,子类才能返回不同类型的产品,同时基类中的工厂方法还应将其返回类型声明为这一共有接口

For example, both Trunk and Ship classes should implement the Transpot interface, which declares a method called deliver. 每个类都将以不同的方式来实现该方法 deliver: trucks deliver cargo by land, ships deliver cargo by sea. The factory method in RoadLogistics class return truck objects, where the factory method in SeaLogistics return ships. 陆地运输工厂返回卡车对象,海路运输工厂返回轮船对象

The code that uses the factory method (often called the client code) doesn’t see a difference between the actual products returned by various subclasses. The client treats all the products as abstract Transport. The client knows that all transport objects are supposed to have the deliver method, but exactly how it works isn’t important to the client. 客户端无需关系其具体的实现方法

Pros and Cons

  • Pros
    • Avoid tight coupling between the creator and the concrete products. 解耦
    • Single Responsibility Principle. You can move the product creation code into one place in the program, making the code easier to support. 单一职责原则
    • Open/Closed Principle. You can introduce new types of products into the program without breaking existing client code. 开闭原则
  • Cons
    • The code may become more complicated since you need to introduce a lot of new subclasses to implement the pattern. The best case scenario is when you’re introducing the pattern into an existing hierarchy of creator classes. 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,增加了系统的复杂度

Implementations

工厂方法模式的主要角色:

  • Abstract Factory 抽象工厂: 提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • Concrete Factory 具体工厂: 主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • Product 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
  • Concrete Product 具体产品: 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

Product 抽象产品

Coffee.java
package pers.jiacheng.patterns.factory.factory_method;

public abstract class Coffee {
public abstract String getName();

public void addSugar() {
System.out.println("add sugar");
}

public void addMilk() {
System.out.println("add milk");
}
}

Concrete Product 具体产品

LatteCoffee.java
package pers.jiacheng.patterns.factory.factory_method;

public class LatteCoffee extends Coffee {
@Override
public String getName() {
return "Latte Coffee";
}
}
AmericanCoffee.java
package pers.jiacheng.patterns.factory.factory_method;

public class AmericanCoffee extends Coffee {
@Override
public String getName() {
return "American Coffee";
}
}

Abstract Factory 抽象工厂

CoffeeFactory.java
package pers.jiacheng.patterns.factory.factory_method;

public interface CoffeeFactory {
Coffee createCoffee();
}

Concrete Factory 具体工厂

LatteCoffeeFactory.java
package pers.jiacheng.patterns.factory.factory_method;

public class LatteCoffeeFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}

}
AmericanCoffeeFactory.java
package pers.jiacheng.patterns.factory.factory_method;

public class AmericanCoffeeFactory implements CoffeeFactory {
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}

}

咖啡店类

CoffeeStore.java
package pers.jiacheng.patterns.factory.factory_method;

public class CoffeeStore {
private CoffeeFactory factory;

public void setFactory(CoffeeFactory factory) {
this.factory = factory;
}

public Coffee orderCoffee() {
Coffee coffee = factory.createCoffee();
coffee.addMilk();
coffee.addSugar();
return coffee;
}
}

测试类

Client.java
package pers.jiacheng.patterns.factory.factory_method;

public class Client {
public static void main(String[] args) {
// 1. create a coffee shop
CoffeeStore store = new CoffeeStore();

// 2. create a coffee factory
AmericanCoffeeFactory factory = new AmericanCoffeeFactory();
store.setFactory(factory);

// 3. order coffee
Coffee coffee = store.orderCoffee();
System.out.println(coffee.getName()); // American Coffee
}
}