设计模式——简单工厂、工厂方法、抽象工厂(TypeScript版)

463 阅读6分钟

对于工厂模式主要包含三种:简单工厂模式、工厂方法模式、抽象工厂模式。简单工厂模式是最简单实用的模式,利用工厂对象决定创建出哪一种产品类的实例,实际上有违ocp原则;为了弥补简单工厂模式的不足,提出工厂方法模式,通过新增工厂类来实现扩展,满足ocp原则;抽象工厂模式是将简单工厂模式和工厂方法模式进行整合,由工厂方法模式中一个工厂类只负责生产一个具体产品扩展为一个具体工厂可以生产一组相关产品。下面将逐一对这三种模式进行阐述。

1. 简单工厂模式

1.1 定义

定义一个创建对象的类,由这个类来封装实例化对象的行为(代码)

1.2 类图

简单工厂模式把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化。

1.3 优点

这样做能把客户类和具体子类的实现解耦,客户类不再需要知道哪些子类以及应当实例化哪个子类。客户类往往有多个,如果不使用简单工厂,那么所有的客户类就要知道所有子类的细节,而且一旦子类发生改变,例如增加子类,那么所有的客户类都要进行修改。

1.4 缺点

  1. 工厂类集中了所有产品的创建逻辑,职责过重,一旦异常,整个系统将受影响。
  2. 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度。
  3. 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。

1.5 使用场景

  1. 工厂类负责创建的对象比较少,因为不会造成工厂方法中的业务逻辑过于复杂。
  2. 客户端只知道传入工厂类的参数,对如何创建对象不关心。

1.6 代码实现

// 抽象产品接口
interface Product{}

// 具体产品一
class ConcreteProduct1 implements Product {
    constructor(){}
}

// 具体产品二
class ConcreteProduct2 implements Product {
    constructor(){}
}

// 简单工厂
class SimpleFactory {
    public static createProduct(type : number) : Product {
        let product = null;
        if (type === 1) {
            product = new ConcreteProduct1();
        } else if ( type === 2) {
            product = new ConcreteProduct2();
        }

        return product;
    }
}

// 使用
let product = SimpleFactory.createProduct(1);

2. 工厂方法模式

2.1 定义

定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。

2.2 类图

2.3 优点

  1. 用户只需要关心产品对应的工厂,甚至无需关心创建细节或具体产品类的类名。
  2. 能自主决定如何创建哪种产品对象,而创建细节都封装在具体工厂内部。
  3. 在系统要添加新的产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,只要添加一个具体工厂和具体产品即可,从而提高系统的可扩展性(符合开闭原则)。

2.4 缺点

  1. 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
  2. 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度。

2.5 使用场景

  1. 所有需要生成对象的地方都可以使用(需要权衡是否需要增加一个工厂类,因为会增加代码的复杂度)
  2. 需要灵活,可扩展的框架时
  3. 在异构项目中使用
  4. 在测试驱动开发的架构下

2.6 代码实现

// 抽象产品接口
interface Product{
    method1() : void;
    method2() : void;
}

// 具体产品一
class ConcreteProduct1 implements Product {
    constructor(){}
    method1() {

    }
    method2() {

    }
}

// 具体产品二
class ConcreteProduct2 implements Product {
    constructor(){}
    method1() {

    }
    method2() {
        
    }
}

// 抽象工厂
abstract class Creator {
    public abstract createProduct(type : number) : Product;
}

// 具体工厂
class ConcreteCreator extends Creator {
    constructor(){
        super();
    }

    public createProduct(type : number) : Product {
        let product = null;
        if (type === 1) {
            product = new ConcreteProduct1();
        } else if (type === 2) {
            product = new ConcreteProduct2();
        }
        return product;
    }
}

// 使用
const creator : Creator = new ConcreteCreator();
const myProduct : Product = creator.createProduct(1)

3. 抽象工厂模式

首先用一张图先来理解一下两个概念:产品族和产品等级结构。

产品族:指由同一个工厂生产的,位于不同产品等级结构中的一组产品。例如Adidas生产的旅游鞋、帆布鞋、板鞋就是一个产品族。

产品等级结构:就是指产品的继承结构,例如板鞋这一列就是一个产品等级结构。

3.1 定义

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类。

3.2 类图

3.3 优点

  1. 隔离了具体类的生成,使得客户端不需要知道什么被创建。
  2. 当一个产品族的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族的对象。
  3. 抽象工厂模式增加新的产品族很容易,无需修改已有系统,符合开闭原则。

3.4 缺点

增加新的产品结构很麻烦,需要对原有系统进行大规模的修改,甚至需要修改抽象层代码,违背了开闭原则。

3.5 使用场景

  1. 当一个系统不依赖于产品类实例如何被创建、组合和表达的细节,用户无需关心对象的创建过程,将对象的创建和使用解耦。
  2. 系统中有多于一个的产品族,但每次只需要使用其中某一个产品族,可以通过配置文件等动态地改变产品族,也很方便的增加新的产品族。
  3. 产品等级结构稳定,设计完成后,不会向系统增加i新的产品等级结构或者删除已有的产品等级结构。

3.6 代码实现

// 抽象工厂接口
interface AbstractFactory {
    createProductA() : AbstractProductA;
    createProductB() : AbstractProductB;
}

// 抽象产品A接口
interface AbstractProductA {}

// 抽象产品B接口
interface AbstractProductB {}

// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
    constructor() {}
    public createProductA() : AbstractProductA {
        return new ConcreteProductA1();
    }
    public createProductB() : AbstractProductB {
        return new ConcreteProductB1();
    }
}

// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
    constructor() {}
    public createProductA() : AbstractProductA {
        return new ConcreteProductA2();
    }
    public createProductB() : AbstractProductB {
        return new ConcreteProductB2();
    }
}

// 具体产品A1
class ConcreteProductA1 implements AbstractProductA {}
// 具体产品A2
class ConcreteProductA2 implements AbstractProductA {}
// 具体产品B1
class ConcreteProductB1 implements AbstractProductB {}
// 具体产品B2
class ConcreteProductB2 implements AbstractProductA {}

// 使用
const factory1 : AbstractFactory = new ConcreteFactory1();
const factory2 : AbstractFactory = new ConcreteFactory2();
const productA1 : AbstractProductA = factory1.createProductA();
const productA2 : AbstractProductA = factory2.createProductA();
const productB1 : AbstractProductB = factory1.createProductB();
const productB2 : AbstractProductB = factory2.createProductB();