工厂方法模式

工厂方法模式

  • by Head First 设计模式

    工厂方法模式定义了一个创建对象的接口,但是由子类决定要创建的对象是哪一个。工厂方法把类的实例化推迟到 子类。

  • by Dive into Design Patterns

    Factory Method is a creation(al) 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.

工厂模式指定工厂仅仅能创建特定类型的产品。

设计原则 #

工厂方法很简单,实际上就是抽取客户中实例化对象的代码,利用"对象工厂"来进行实例化。这样做有几个明显的好处:

  1. 降低耦合:创建对象的过程和具体的业务解耦。
  2. 基本上满足开-闭原则:如果使用工厂,创建对象的逻辑变动或者所需要创建对象变动对客户的代码影响不大。
  3. 满足依赖倒置原则
    • 依赖抽象而不是依赖具体实现类。不管是高层组件(接口)还是低层组件(对象),都应该依赖抽象。 高层组件不应该直接依赖具体的对象。
    • 依赖倒置原则

UML简图 #

classDiagram

class Product {
  << Interface >>
  +method1()
  +method2()
}
Product ..> ProductCreator
class ProductCreator {
  << Abstract >>
  +factoryMethod() Product
  +otherMethod()
}

ConcreteProductA ..|> Product
class ConcreteProductA {
  +methodA()
  +methodB()
}

ConcreteProductB ..|> Product
class ConcreteProductB {
  +methodA()
  +methodB()
}

ProductACreator --|> ProductCreator
class ProductACreator {
  +factoryMethod() Product
  +otherMethod()
}

ProductBCreator --|> ProductCreator
class ProductBCreator {
  +factoryMethod() Product
  +otherMethod()
}

示例代码 #

在本例中,假如要创建一个按扭控件,但对于不同的OS,可能控件的样式有所区别,因此,需要针对不同的OS来创建不同的实例。

我们可以使用工厂模式来实现。

需要创建的对象 #

下面的代码展示了产品(Button1)接口及其不同的实现:

 1public interface Button1 {
 2
 3    void render();
 4
 5    void onClick();
 6}
 7
 8public class Button1HTML implements Button1 {
 9    @Override
10    public void render() {
11        System.out.println("=====> render HTML Button.");
12    }
13
14    @Override
15    public void onClick() {
16        System.out.println("====> click HTML button.");
17    }
18}
19
20public class Button1Win implements Button1 {
21    @Override
22    public void render() {
23        System.out.println("<===== render windows button.");
24    }
25
26    @Override
27    public void onClick() {
28        System.out.println("<===== click windows button.");
29    }
30}

对象工厂 #

这就是创建对象的工厂,它有一个抽象类,有一个工厂方法(创建产品),但是它不直接创建产品,而是把创建产品的任务交给子类。

 1public abstract class Dialog {
 2
 3    /** 工厂方法 button factory */
 4    abstract Button1 createButton();
 5
 6    /**
 7     *  请注意,创建者的主要职责并非是创建产品。其中通常会包含一些核心业务
 8     *  逻辑,这些逻辑依赖于由工厂方法返回的产品对象。子类可通过重写工厂方
 9     *  法并使其返回不同类型的产品来间接修改业务逻辑。
10     */
11    void render(){
12        Button1 button1 = createButton();
13        button1.onClick();
14        button1.render();
15    }
16}
17
18public class DialogHTML extends Dialog{
19    @Override
20    Button1 createButton() {
21        return new Button1HTML();
22    }
23}
24
25public class DialogWin extends Dialog{
26    @Override
27    Button1 createButton() {
28        return new Button1Win();
29    }
30}

测试类 #

 1public class TestDialog {
 2
 3    public static void main(String[] args) {
 4        String os = "windows";
 5        if (args != null && args.length != 0) os = args[0];
 6        Dialog dialog = init(os);
 7        dialog.render();
 8    }
 9
10    private static Dialog init( String os) {
11        System.setProperty("current.OS", os);
12        Dialog dialog;
13        if (System.getProperty("current.OS").equals("web")){
14            dialog = new DialogHTML();
15        }else{
16            dialog = new DialogWin();
17        }
18        return dialog;
19    }
20}
21///:~
22//<===== click windows button.
23//<===== render windows button.
24//

模式总结 #

Generated by gemini, revised.

工厂方法模式是一种创建型设计模式,它定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。不过工厂模式的工厂职责相对单一,仅能创建指定对象。

工厂方法模式的核心思想是: 将对象的创建推迟到子类中,让子类决定创建哪个具体的产品对象。父类定义创建对象的通用接口,子类实现具体的创建逻辑。

优点:

  • 符合开闭原则: 可以通过增加新的具体工厂和具体产品来扩展系统,而无需修改现有的代码。

  • 降低耦合度: 客户端与具体产品类解耦,只需依赖抽象产品接口和抽象工厂接口。

  • 提高了灵活性: 可以灵活地选择创建哪个具体产品,而无需修改客户端代码。

  • 更好的代码组织: 将对象的创建逻辑分散到各个具体工厂中,使代码更易于维护和理解。

缺点:

  • 类的数量增加: 每个产品都需要一个对应的工厂类,可能导致类的数量增加。

  • 增加了系统的复杂度: 引入工厂方法模式会增加系统的抽象层次。

适用场景:

  • 当一个类不知道它所需要的对象的类时。

  • 当一个类希望由它的子类来指定创建的对象时。

  • 当将对象的创建逻辑集中到一个地方,并且希望允许子类来定制对象的创建过程时。

简单比喻:

想象你想要购买不同类型的汽车:轿车、SUV、跑车。

  • Product(抽象产品): 汽车接口,定义了 drive() 方法。

  • ConcreteProduct(具体产品): 轿车、SUV、跑车,每个类都实现了汽车接口。

  • Creator(抽象创建者): 汽车4S店,定义了 orderCar() 和 createCar() 方法,其中 createCar() 是工厂方法。

  • ConcreteCreator(具体创建者): 轿车4S店、SUV4S店、跑车4S店,每个店都实现了 createCar() 方法,但创建的汽车类型不同。

你只需要告诉汽车4S店你想要什么类型的汽车,4S店(工厂)就会为你准备好汽车,而你不需要知道汽车是如何制造的。

开发建议 #

《深入设计模式》中关于工厂模式的介绍