跳到主要内容

13 篇博文 含有标签「设计模式」

设计模式

查看所有标签

抽象工厂模式 (Abstract Factory)

· 阅读需 4 分钟

抽象工厂模式是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类。

优点:

  1. 你可以确保同一工厂生成的产品相互匹配。
  2. 你可以避免客户端和具体产品代码的耦合。
  3. 单一职责原则。 你可以将产品生成代码抽取到同一位置, 使得代码易于维护。
  4. 开闭原则。 向应用程序中引入新产品变体时, 你无需修改客户端代码。

缺点:

  1. 由于采用该模式需要向应用中引入众多接口和类, 代码可能会比之前更加复杂。

示例

抽象工厂模式的特点是,定义一个抽象工厂类或者接口,由此定义了规范的工厂方法(造桌子、造椅子),将此规范应用于具体的工厂类,例如现代风格工厂和复古风格工厂,生产出不同风格的桌子椅子,他们具有相同的规范,能坐、能放东西。想创建新的风格家具,只需要编写新风格的工厂类并实现抽象工厂接口,不用改动任何已有代码。

抽象工厂,构造方法返回的是抽象的产品。客户端代码,也是与抽象的产品进行交互,无需知道其内部细节,只需要知道椅子可以 sitOn,桌子可以 putSomething

interface AbstractFactory {
createChair(): AbstractChair;
createDesk(): AbstractDesk;
}

interface AbstractChair {
type: string;
sitOn(): void;
}

interface AbstractDesk {
type: string;
putSomething(): void;
mixedFurniture(chair: AbstractChair): void;
}

class MordernChair implements AbstractChair {
type = 'MordernChair';
sitOn() {
console.log('Sitting on Mordern chair.');
}
}

class ClassicChair implements AbstractChair {
type = 'ClassicChair';
sitOn() {
console.log('Sitting on Classic chair.');
}
}

class MordernDesk implements AbstractDesk {
type = 'MordernDesk';
putSomething() {
console.log('Put something on Mordern desk.');
}
mixedFurniture(chair: AbstractChair): void {
console.log(`Combo taste: ${chair.type} ${this.type}`);
}
}
class ClassicDesk implements AbstractDesk {
type = 'ClassicDesk';
putSomething() {
console.log('Put something on Classic desk.');
}
mixedFurniture(chair: AbstractChair): void {
console.log(`Combo taste: ${chair.type} ${this.type}`);
}
}

class MordernStyleFactory implements AbstractFactory {
createChair(): AbstractChair {
return new MordernChair();
}
createDesk(): AbstractDesk {
return new MordernDesk();
}
}

class ClassicStyleFactory implements AbstractFactory {
createChair(): AbstractChair {
return new ClassicChair();
}
createDesk(): AbstractDesk {
return new ClassicDesk();
}
}

// 客户端代码通过抽象类型与工厂和产品进行交互,这使得耦合度很低
function ClientCode(factory: AbstractFactory) {
// 根据传入的工厂,创建对应风格的家具
const chair = factory.createChair();
const desk = factory.createDesk();
chair.sitOn();
// 桌椅混合套餐
desk.mixedFurniture(chair);
}

// 现代风格工厂
ClientCode(new MordernStyleFactory());

工厂方法模式 (Factory Method)

· 阅读需 4 分钟

工厂方法模式是一种创建型设计模式,在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。

客户端将由不同工厂创建的所有产品都视为抽象的,客户端知道所有产品都提供的交付方法,但是并不关心其具体实现方式。也就是说,产品要有统一的接口,让客户知道怎么用,但不需要知道所调用方法的内部逻辑。如果某一天需要添加新的产品,不需要破坏原有代码,写新的工厂类来创建新产品即可,产品仍然是遵循统一的接口,对客户来说,使用并没有变化。

优点:

  1. 可以避免创建者和具体产品之间的紧密耦合。
  2. 单一职责原则。可以将产品创建代码放在程序的单一位置,从而使得代码更容易维护。
  3. 开闭原则。无需更改现有客户端代码,你就可以在程序中引入新的产品类型。

缺点:

  1. 应用工厂方法模式需要引入许多新的子类,代码可能会因此变得更复杂。

示例

以下代码有两个重点,分别是工厂和产品。

定义了一个 Creator 抽象类,包含了抽象工厂方法,和一些业务代码;具体的 ConcreteCreatorA 和 ConcreteCreatorB 继承该抽象类,实现各自具体的工厂方法用于创建不同产品。

定义了一个 Product 接口,制定了产品的特征;规定产品有一个 operation() 函数;具体的产品 ConcreteProductA 和 ConcreteProductB 实现了该接口,各自的 operation() 内部代码都不相同。

// Product 产品接口,定义了产品具有 operation 特征
// ConcreteProductA ConcreteProductB 实现 Product 接口,是具体的产品实体类。
interface Product {
operation(): string;
}

class ConcreteProductA implements Product {
public operation(): string {
return '[Result of ConcreteProductA]';
}
}

class ConcreteProductB implements Product {
public operation(): string {
return '[Result of ConcreteProductB]';
}
}

/**
* 虽然名字叫创建者,但是它的主要责任并不是创建产品,
* 通常它包含一些依赖于 Product 对象的核心业务逻辑,Product 对象由工厂方法返回。
* 子类可以通过重写工厂方法、返回不同类型的 Product,间接地改变业务逻辑。
*/
abstract class Creator {
public abstract factoryMethod(): Product;

public someOperation() {
const product = this.factoryMethod();
console.log('Do something, ' + product.operation());
}
}

class ConcreteCreatorA extends Creator {
public factoryMethod(): ConcreteProductA {
return new ConcreteProductA();
}
}

class ConcreteCreatorB extends Creator {
public factoryMethod(): ConcreteProductB {
return new ConcreteProductB();
}
}

/**
* 客户端代码,无需了解 Creator 类的内部逻辑,直接无脑调用 someOperation 函数;
* 该函数写在了 Creator 类中,其业务逻辑依赖于工厂方法创建的 Product 对象;
*/
function ClientCode(creator: Creator) {
creator.someOperation();
}

ClientCode(new ConcreteCreatorA());
ClientCode(new ConcreteCreatorB());

输出结果:

Do something, [Result of ConcreteProductA]
Do something, [Result of ConcreteProductB]

单例模式 (Singleton Pattern)

· 阅读需 1 分钟

单例模式提供方法,返回相同的缓存实例对象。

定义一个 Singleton 类,它应该具备以下特征:

  • 实例对象私有,不可被直接访问
  • 实现静态公有的 getInstance() 方法获取实例对象
  • 类不可使用 new 来实例化

示例

单例模式示例代码如下:

class Singleton {
private static instance: Singleton;

// 私有构造函数,不可用 new 实例化
private constructor() { }

public static getInstance(): Singleton {
if (!this.instance) {
this.instance = new Singleton();
}

return Singleton.instance;
}

// 单例也有一些业务逻辑,在实例上执行
public printHello() {
console.log('Hello');
}
}

const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
s1.printHello(); // Hello
s1 === s2; // true

可以出 s1s2 引用的是同一个实例对象。