前端工程中的设计模式应用

news2024/11/30 11:32:10

8bee58143225525314ba9af0a5e0ae18.gif

本文旨在系统性介绍一下23种设计模式,给出通俗易懂的案例、结构图及代码示例,这也是我自身学习理解的过程。或许其中的几种设计模式写的并不是很清晰明了易懂,更详细的可根据提到的参考文献进行深入学习。

37b0bf9d277c01ef0b7955755d129514.png

什么是设计模式

设计模式这个概念是由一本名为《设计模式:可复用面向对象软件的基础》的书推广而来,这本书在1994年由四个C++工程师编写的。这本书探讨了面向对象的编程的能力和陷阱,并介绍了23种可以用来解决编程问题的模式。这些模式并不是算法或者具体的实现,它们更像是想法、观点和抽象,辅助我们去解决一些特定问题。但是这些模式建立在C++的OOP的基础之上,当使用更现代的编程语言如JavaScript时,模式可能不等效,甚至给代码添加了不必要的限制,但是我们仍然可以把这些模式当做一些编程知识来学习了解。我们学习使用这些模式的目的是实现代码的高内聚和低耦合,提高代码的复用性,让代码更容易的被他人理解并保证代码的可靠性。

9a3e02b804a085218ac3284b7ebd786d.png

23种设计模式简介

  创建型(Creational)(5种)

提供创建对象的机制, 增加已有代码的灵活性和可复用性。

  • 单例模式(Singleton)

保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

  • 原型模式(Prototype)

允许把一个对象作为蓝图创建另一个对象,新对象继承原对象的属性和方法。

  • 生成器模式(Builder)

分“步骤”创建对象。

  • 工厂方法模式(Factory Method)

提供创建对象的接口,对象被创建后可以修改。

  • 抽象工厂模式(Abstract Factory)

允许在不指定具体类的情况下生成一系列相关的对象。

  结构型(Structural)(7种)

介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效。

  • 桥接模式(Bridge)

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

  • 外观模式(Facade)

给库、框架以及其他复杂的类集提供简化的接口。

  • 组合模式(Composite)

将对象组合成树形结构来表现整体和部分的层次结构

  • 装饰器模式(Decorator)

通过增加一个修饰对象来包裹原来的对象,从而给原来的对象添加新的行为

  • 适配器模式(Adapter)

允许两个接口不兼容的对象相互交互

  • 代理模式(Proxy)

为另一个对象提供替代或者占位符

  • 享元模式(Flyweight)

运用共享技术来有效地支持大量细粒度对象的复用,以减少创建的对象的数量

  行为型(Behavioral)(11种)

负责对象间的高效沟通和职责委派。

  • 迭代器模式(Iterator)

用于遍历集合的元素

  • 解释器模式(Interpreter )

给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子

  • 观察者模式(Observer)

定义一个订阅机制来通知多个对象它们在观察的对象发生的任何事件

  • 中介者模式(Mediator)

用一个中介对象来封装多个对象之间的复杂交互

  • 访问者模式(Visitor)

针对于对象结构中的元素,定义在不改变该对象的前提下访问其结构中元素的新方法。

  • 状态模式(State)

当一个对象的内部状态发生改变时,会导致其行为的改变,这看起来像是改变了对象

  • 备忘录模式(Memento)

允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。

  • 策略模式(Strategy)

定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

  • 模板方法模式(Template Method)

父类中定义一组操作算法骨架,而将一些实现步骤延迟到子类中,使得子类可以不改变父类的算法结构的同时,重新定义算法中的某些实现步骤。

  • 职责链模式(Chain of Responsibility)

将请求通过处理链传递,链条上的每一个处理程序决定要么处理请求,要么将请求传递给链条上的下一个处理程序。

  • 命令模式(Command)

将请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

704a6b253ee2197c5726ade860ab60d8.png

设计模式细解

  创建型

创建型模式提供了创建对象的机制, 能够提升已有代码的灵活性和可复用性。

  • 单例模式

单例模式是一种创建型设计模式,它保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

举个现实的例子,比如一个国家只有一个官方政府。不管组成政府的每个人的身份是什么, “某政府” 这一称谓总是鉴别那些掌权者的全局访问节点。

单例模式结构:

6c639eea863988c9f1dc9f78a0ed6301.png

代码实现:

class Singleton {
  constructor() {
    this.instance = null; // 单例模式的标识 
  }


  getInstance() {
    if (!this.instance) {
      this.instance = new Singleton(name);
    }
    return this.instance;
  }
}


function clientCode() {
    const s1 = Singleton.getInstance();
    const s2 = Singleton.getInstance();


    if (s1 === s2) {
        console.log('同一个实例');
    } else {
        console.log('不同实例');
    }
}


clientCode(); // 同一个实例
  • 原型模式

原型模式一种创建型设计模式, 它能够复制已有对象,获取原有对象的属性和方法,而又无需使代码依赖它们所属的类。

举个现实的例子,比如细胞的有丝分裂。有丝分裂会产生一对完全相同的细胞。原始细胞就是一个原型, 它在复制体的生成过程中起到了推动作用。

原型模式结构:

9eb2908942ddf5b86d49a56b9e1b98e1.png

代码实现:

class Prototype {
    constructor(name) {
        this.name = name;
    }


    setName(name) {
        this.name = name;
    }


    clone() { 
        return new Prototype(this.name);
    }
}


function clientCode() {
    const p1 = new Prototype('原型模式');
    const p2 = p1.clone();


    if(p1.name === p2.name) {
      console.log('属性复制成功');
    }


    p2.setName('复制的原型模式');
    if(p2.name === '复制的原型模式') {
      console.log('方法复制成功,并不依赖于原先的类');
    }


}


clientCode(); // 属性复制成功   方法复制成功,并不依赖于原先的类
  • 生成器模式

构造器模式是一种创建型设计模式, 它能够分步骤创建复杂对象,可以使用相同的创建代码生成不同类型和形式的对象。

举个现实的例子,比如汽车的制造,A工厂生产轮胎,B工厂生产车门,C工厂生产玻璃,...  最终Z工厂负责组装这些零件,出厂一辆完整的汽车。

生成器模式结构:

7be2a3da082b4f0f3e2668dd0709b3ee.png

简而言之,生成器模式可以概括为两部分,第一部分是具体生成器(ConcreteBuilder)负责new Product,并提供处理Product的各种方法;第二部分主管(Director)负责处理Product的各种方法的调用。

代码实现:

interface Builder {  // 指定创建product对象不同部分的方法
    producePartA(): void;
    producePartB(): void;
    producePartC(): void;
}
// 要创建的产品
class Product {
    public parts: string[] = [];
    public listParts(): void {
        console.log(`Product parts: ${this.parts.join(', ')}\n`);
    }
}
// 具体生成器1
class ConcreteBuilder implements Builder {
    private product: Product1; // 空的产品对象,用于后续的组装
    constructor() {
        this.reset();
    }
    public reset(): void {
        this.product = new Product();
    }
// 所有的生产步骤都是对同一个product实例进行操作
    public producePartA(): void {
        this.product.parts.push('PartA1');
    }
    public producePartB(): void {
        this.product.parts.push('PartB1');
    }
    public producePartC(): void {
        this.product.parts.push('PartC1');
    }
// 获取产品的方法
    public getProduct(): Product {
        const result = this.product;
        this.reset(); // 调用重置方法,做好生产下一个产品的准备,但这并不是必须的
        return result;
    }
}
// 定义创建步骤的执行顺序, 其中生成器负责提供这些步骤的实现。
class Director {
    private builder: Builder;
    public setBuilder(builder: Builder): void {
        this.builder = builder;
    }
    public buildMinimalViableProduct(): void {
        this.builder.producePartA();
    }
    public buildFullFeaturedProduct(): void {
        this.builder.producePartA();
        this.builder.producePartB();
        this.builder.producePartC();
    }
}
// 客户端代码
function clientCode(director: Director) {
    const builder = new ConcreteBuilder(); 
    director.setBuilder(builder); // 将主管类与具体生成器进行关联


    console.log('生成一个基础产品:');
    director.buildMinimalViableProduct();
    builder.getProduct().listParts(); // Product parts: PartA1


    console.log('生成一个完整产品:');
    director.buildFullFeaturedProduct();
    builder.getProduct().listParts(); // Product parts: PartA1, PartB1, PartC1


   // builder类也可以不依赖于Director,可以直接调用其内部的方法
    console.log('生成其他定制产品:');
    builder.producePartA();
    builder.producePartC();
    builder.getProduct().listParts(); // Product parts: PartA1, PartC1
}


const director = new Director();
clientCode(director);
  • 工厂方法模式

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

工厂方法模式结构:

138aaa32f1d8c2b67441dc6ff6fc64c3.png

代码实现:

interface Product { // 声明了所有产品必须实现的操作
    operation(): string;
}
// 创建者类,声明返回产品对象的工厂方法
abstract class Creator {
    public abstract factoryMethod(): Product;
    public someOperation(): string {
        const product = this.factoryMethod(); // 调用工厂方法创建一个产品对象
        return `Creator: 同一个Creator的代码被应用在 ${product.operation()}`;
    }
}
// 具体创建者将重写工厂方法,以改变其所返回的产品类型
class ConcreteCreator1 extends Creator {
    public factoryMethod(): Product {
        return new ConcreteProduct1();
    }
}
class ConcreteCreator2 extends Creator {
    public factoryMethod(): Product {
        return new ConcreteProduct2();
    }
}
// 具体产品需提供产品接口的各种实现
class ConcreteProduct1 implements Product {
    public operation(): string {
        return '{ConcreteProduct1的结果}';
    }
}
class ConcreteProduct2 implements Product {
    public operation(): string {
        return '{ConcreteProduct2的结果}';
    }
}
// 客户端代码
function clientCode(creator: Creator) {
    console.log(creator.someOperation());
}


console.log('App: ConcreteCreator1 启动');
clientCode(new ConcreteCreator1());
//Creator: 同一个Creator的代码被应用在 {ConcreteProduct1的结果}


console.log('App: Launched with the ConcreteCreator2.');
clientCode(new ConcreteCreator2()); 
//Client: I'm not aware of the creator's class, but it still works.
// Creator: 同一个Creator的代码被应用在 {ConcreteProduct2的结果}

简而言之,客户端传入的是具体生成器,然后创建出一个新商品,不同的具体生成器可以产出不同的具体商品。也就是父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。

  • 抽象工厂模式

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

抽象工厂模式结构:

7e8064ea63bfb8f5dae2441ba7fe23da.png

代码实现:

// 抽象工厂接口,声明可返回不同抽象产品的方法
interface AbstractFactory {
    createProductA(): AbstractProductA;
    createProductB(): AbstractProductB;
}
// 抽象产品接口
interface AbstractProductA {
    usefulFunctionA(): string;
}
interface AbstractProductB {
    usefulFunctionB(): string;
    anotherUsefulFunctionB(collaborator: AbstractProductA): string;
}
// 具体工厂 可生成属于同一变体的系列产品
class ConcreteFactory1 implements AbstractFactory {
    public createProductA(): AbstractProductA {
        return new ConcreteProductA1();
    }
    public createProductB(): AbstractProductB {
        return new ConcreteProductB1();
    }
}
class ConcreteFactory2 implements AbstractFactory {
    public createProductA(): AbstractProductA {
        return new ConcreteProductA2();
    }
    public createProductB(): AbstractProductB {
        return new ConcreteProductB2();
    }
}
// 具体产品 由相应的具体工厂创建
class ConcreteProductA1 implements AbstractProductA {
    public usefulFunctionA(): string {
        return '这里是A1产品';
    }
}
class ConcreteProductA2 implements AbstractProductA {
    public usefulFunctionA(): string {
        return '这里是A2产品';
    }
}
class ConcreteProductB1 implements AbstractProductB {
    public usefulFunctionB(): string {
        return '这里是B1产品';
    }
    public anotherUsefulFunctionB(collaborator: AbstractProductA): string {
        const result = collaborator.usefulFunctionA();
        return `这里是B1产品合作 (${result})`;
    }
}
class ConcreteProductB2 implements AbstractProductB {
    public usefulFunctionB(): string {
        return '这里是B2产品';
    }
    public anotherUsefulFunctionB(collaborator: AbstractProductA): string {
        const result = collaborator.usefulFunctionA();
        return `这里是B2产品合作 (${result})`;
    }
}
// 客户端代码 仅通过抽象类型AbstractFactory使用工厂和产品
function clientCode(factory: AbstractFactory) {
    const productA = factory.createProductA();
    const productB = factory.createProductB();
    console.log(productB.usefulFunctionB());
    console.log(productB.anotherUsefulFunctionB(productA));
}
clientCode(new ConcreteFactory1()); // 这里是B1产品 // 这里是B1产品合作(A1)
clientCode(new ConcreteFactory2()); // 这里是B2产品 // 这里是B2产品合作(A2)

简而言之,客户端的入参是具体工厂(具体工厂是抽象工厂的实现),具体工厂会生成具体产品。抽象工厂为你提供了一个接口, 可用于创建每个系列产品的对象。只要代码通过该接口创建对象, 那么你就不会生成与应用程序已生成的产品类型不一致的产品。

  结构型

结构型模式介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效。

  • 桥接模式

桥接模式是一种结构型设计模式, 可将一个大类或一系列紧密相关的类拆分为不同的层次结构, 从而能在开发时分别使用。

桥接模式结构:

ed16dbb3fabab2c932968ac3f33694c6.png

代码实现:

// 定义了所有Implementation类的接口
interface Implementation {
    operationImplementation(): string;
}
class Abstraction {// 提供对Implementation的引用,并将所有的实际工作委托给它
    protected implementation: Implementation;
    constructor(implementation: Implementation) {
        this.implementation = implementation;
    }
    public operation(): string {
        const result = this.implementation.operationImplementation();
        return `抽象部分: 基础操作: ${result}`;
    }
}
// 在不改变Implementation类的前提下继承Abstraction
class ExtendedAbstraction extends Abstraction {
    public operation(): string {
        const result = this.implementation.operationImplementation();
        return `继承的抽象部分: 继承的操作:${result}`;
    }
}
class ConcreteImplementationA implements Implementation {
    public operationImplementation(): string {
        return '具体实现A: 这里是A的结果';
    }
}
class ConcreteImplementationB implements Implementation {
    public operationImplementation(): string {
        return '具体实现B: 这里是B的结果';
    }
}
// 客户端代码
function clientCode(abstraction: Abstraction) {
    console.log(abstraction.operation());
}


let implementation = new ConcreteImplementationA();
let abstraction = new Abstraction(implementation);
clientCode(abstraction); // 抽象部分:基础操作:具体实现A: 这里是A的结果.
implementation = new ConcreteImplementationB();
abstraction = new ExtendedAbstraction(implementation);
clientCode(abstraction); // 继承的抽象部分: 继承的操作: 具体实现B: 这里是B的结果.

简单来说,对于一个复杂庞大的系统,可以将其分层,第一层是抽象层,第二层为具体层,抽象层可以把对自己的调用委派给实现层实现,而所有的实现层都具有统一接口,所以实现层可以在抽象部分内部进行相互替换。

  • 外观模式

外观模式是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口。

举个现实的例子,淘宝就是一个外观,它提供了你购物、支付、送花上门等接口。

外观模式结构:

99ee04a195ad20e1bc8ac3581e9d5e77.png

代码实现:

// 为一个或多个子系统的复杂逻辑提供简单接口
class Facade {
    protected subsystem1: Subsystem1;
    protected subsystem2: Subsystem2;
    constructor(subsystem1?: Subsystem1, subsystem2?: Subsystem2) {
        this.subsystem1 = subsystem1 || new Subsystem1();
        this.subsystem2 = subsystem2 || new Subsystem2();
    }
    public operation(): string {
        let result = 'Facade初始化子系统';
        result += this.subsystem1.operation1();
        result += this.subsystem2.operation1();
        result += 'Facade命令子系统执行操作';
        result += this.subsystem1.operationN();
        result += this.subsystem2.operationZ();
        return result;
    }
}
class Subsystem1 {
    public operation1(): string {
        return 'Subsystem1准备好了!';
    }
    public operationN(): string {
        return 'Subsystem1执行!';
    }
}
class Subsystem2 {
    public operation1(): string {
        return 'Subsystem2准备好了';
    }
    public operationZ(): string {
        return 'Subsystem2执行!';
    }
}
// 客户端代码
function clientCode(facade: Facade) {
    console.log(facade.operation());
}
const subsystem1 = new Subsystem1();
const subsystem2 = new Subsystem2();
const facade = new Facade(subsystem1, subsystem2);
clientCode(facade); // Facade初始化子系统 Subsystem1准备好了! Subsystem2准备好了 Facade命令子系统执行操作 Subsystem1执行! Subsystem2执行!
  • 组合模式

组合模式是一种结构型设计模式, 你可以使用它将对象组合成树状结构, 并且能像使用独立对象一样使用它们。

举个现实的例子,比如学校,学校由年级组成,年级由班级组成,班级由学生个体组成。当学校下达重要通知时,是逐级下发的,通过一个个层级的传递,直到每个学生都接收到通知。

组合模式结构:

9a5c715c224df1d5b1ef90fad7e829e4.png

代码示例:

// 描述了 简单 和 复杂 所共有的操作
abstract class Component {
    protected parent!: Component | null;
    public setParent(parent: Component | null) {
        this.parent = parent;
    }
    public getParent(): Component | null {
        return this.parent;
    }
    public add(component: Component): void { }
    public remove(component: Component): void { }
    public isComposite(): boolean {
        return false;
    }
    public abstract operation(): string;
}
// 叶子 执行具体的工作,不再包含子项目
class Leaf extends Component {
    public operation(): string {
        return 'Leaf';
    }
}
// 容器 将具体工作委托给子项目,然后汇总结果
class Composite extends Component {
    protected children: Component[] = [];
    public add(component: Component): void {
        this.children.push(component);
        component.setParent(this);
    }
    public remove(component: Component): void {
        const componentIndex = this.children.indexOf(component);
        this.children.splice(componentIndex, 1);
        component.setParent(null);
    }
    public isComposite(): boolean {
        return true;
    }
    public operation(): string {
        const results = [];
        for (const child of this.children) {
            results.push(child.operation());
        }
        return `Branch(${results.join('+')})`;
    }
}
// 客户端 通过基础接口与所有的组件链接
function clientCode(component: Component) {
    console.log(`RESULT: ${component.operation()}`);
}
const simple = new Leaf();
console.log('Client: 简单的:');
clientCode(simple); // RESULT: Leaf


const tree = new Composite();
const branch1 = new Composite();
branch1.add(new Leaf());
branch1.add(new Leaf());
const branch2 = new Composite();
branch2.add(new Leaf());
tree.add(branch1);
tree.add(branch2);
console.log('Client: 复杂的:');
clientCode(tree); // RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))


function clientCode2(component1: Component, component2: Component) {
    if (component1.isComposite()) {
        component1.add(component2);
    }
    console.log(`RESULT: ${component1.operation()}`);
}
console.log('Client: 当在管理树状结构时,不需要检查组件类');
clientCode2(tree, simple); // RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)

简单来说,组合模式最主要的功能是在整个树状结构上递归调用方法并对结果进行汇总。

  • 装饰器模式

装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。

举个现实的例子,比如天冷加衣服,觉得冷了可以加一件毛衣,还觉得冷可以再加一件羽绒服。这些衣物扩展了你的基本行为,但他们并不是你的一部分,如果不再需要了,可以随时脱掉。如果下雨了,还可以随时再加一件雨衣。

装饰器模式结构:

26733854fdb9ab50e22e8e1e579f1717.png

代码示例:

interface Component { // 定义了可被装饰器修改的操作
    operation(): string;
}
// 具体部件提供了操作的默认实现 但是装饰类可以改变这些操作
class ConcreteComponent implements Component {
    public operation(): string {
        return 'ConcreteComponent';
    }
}
// 
class Decorator implements Component {
    protected component: Component;
    constructor(component: Component) {
        this.component = component;
    }
    public operation(): string {
        return this.component.operation();
    }
}
class ConcreteDecoratorA extends Decorator {
    public operation(): string {
        return `ConcreteDecoratorA(${super.operation()})`;
    }
}
class ConcreteDecoratorB extends Decorator {
    public operation(): string {
        return `ConcreteDecoratorB(${super.operation()})`;
    }
}
// 客户端
function clientCode(component: Component) {
    console.log(`RESULT: ${component.operation()}`);
}
const simple = new ConcreteComponent();
console.log('Client: 简单的部件:');
clientCode(simple); // RESULT: ConcreteComponent


const decorator1 = new ConcreteDecoratorA(simple);
const decorator2 = new ConcreteDecoratorB(decorator1);
console.log('Client: 装饰器部件:');
clientCode(decorator2); // RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))

简答来说,目标对象和装饰器是遵循同一接口的,因此可以使用装饰对对象进行无限次的封装,结果对象将获得所有装饰器装饰后的叠加结果。

  • 适配器模式

适配器模式是一种结构型设计模式, 它能使接口不兼容的对象能够相互合作。

举个现实的例子,电源适配器。

适配器模式结构:

4acd4ee471a6c056e8eaeea9d594fb9f.png

代码示例:

class Target { // 目标
    public request(): string {
        return 'Target: The default target\'s behavior.';
    }
}
class Adaptee { // 被适配者
    public specificRequest(): string {
        return '.eetpadA eht fo roivaheb laicepS';
    }
}
class Adapter extends Target {
    private adaptee: Adaptee;
    constructor(adaptee: Adaptee) {
        super();
        this.adaptee = adaptee;
    }
    public request(): string {
        const result = this.adaptee.specificRequest().split('').reverse().join('');
        return `Adapter: (TRANSLATED) ${result}`;
    }
} 
// 客户端 支持所有遵循Target接口的类
function clientCode(target: Target) {
    console.log(target.request());
}
const target = new Target();
clientCode(target); // Target: 这是默认的目标行为.


const adaptee = new Adaptee();
console.log(`Adaptee: ${adaptee.specificRequest()}`); // Adaptee: .eetpadA eht fo roivaheb laicepS


const adapter = new Adapter(adaptee);
clientCode(adapter); // Adapter: (TRANSLATED) Special behavior of the Adaptee.

简而言之,适配器接收对一个对象的调用,并将其转换为另一个对象可识别的格式和接口。


  • 代理模式

代理模式是一种结构型设计模式, 它能够提供对象的替代品或占位符。代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。

举个现实的例子,我们的数字支付工具比如支付宝支付、微信支付就是现金的代理,他们都实现了同一的接口,均可以用于支付。消费者和被消费者都会非常的满意,因为双方都很便捷。

代理模式结构:

4e49418d0de9f9aab6eb8f631e92a214.png

代码示例:

interface ServiceInterface { // 声明服务接口,实际服务者和代理者要遵循相同的接口
    request(): void;
}
// 实际服务者
class Service implements ServiceInterface {
    public request(): void {
        console.log('实际服务者: 处理请求');
    }
}
// 代理者
class Proxy implements ServiceInterface {
    private service: Service;
    // 代理会维护一个对实际服务者的引用
    constructor(service: Service) {
        this.service = service;
    }
    public request(): void {
        if (this.checkAccess()) {
            this.service.request();
            this.logAccess();
        }
    }
    private checkAccess(): boolean {
        // 在这里执行一些处理
        console.log('代理:触发真正的请求之前进行检查访问');
        return true;
    }
    private logAccess(): void {
        console.log('代理:请求之后的一些处理');
    }
}
// 客户端代码
function clientCode(serviceInterface: ServiceInterface) {
    serviceInterface.request();
}
// 客户端直接调用实际服务者
const service = new Service(); 
clientCode(service); // 实际服务者: 处理请求.
// 客户端通过代理调用实际服务者
const proxy = new Proxy(service);
clientCode(proxy); // 代理:触发真正的请求之前进行检查访问. 实际服务者: 处理请求. 代理:请求之后的一些处理.
  • 享元模式

享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。

享受元模式结构:

3acd87fbb44072a6e8f79fd682b1d6f0.png

代码示例:

// 存储共有状态,接收其余状态
class Flyweight {
  private sharedState: any;
  constructor(sharedState: any) {
    this.sharedState = sharedState;
  }
  public operation(uniqueState): void {
    const s = JSON.stringify(this.sharedState);
    const u = JSON.stringify(uniqueState);
    console.log(`享元: 共享 (${s}),独有 (${u})`);
  }
}
// 创建和管理Flyweight对象
class FlyweightFactory {
  private flyweights: {[key: string]: Flyweight} = <any>{};
  constructor(initialFlyweights: string[][]) {
    for (const state of initialFlyweights) {
      this.flyweights[this.getKey(state)] = new Flyweight(state);
    }
  }
  private getKey(state: string[]): string {
    return state.join('_');
  }
  public getFlyweight(sharedState: string[]): Flyweight {
    const key = this.getKey(sharedState);
    if (!(key in this.flyweights)) {
      console.log('享元工厂: 不能够寻找到享元,创建一个新的');
      this.flyweights[key] = new Flyweight(sharedState);
    } else {
      console.log('享元工厂: 找到了已存在的享元');
    }
    return this.flyweights[key];
  }
  public listFlyweights(): void {
    const count = Object.keys(this.flyweights).length;
    console.log(`享元工厂: 我有 ${count} 个享元:`);
    for (const key in this.flyweights) {
      console.log(key);
    }
  }
}
// 客户端代码  先创建一些预先填充的flyweight
const factory = new FlyweightFactory([
  ['Chevrolet', 'Camaro2018', 'pink'],
  ['Mercedes Benz', 'C300', 'black'],
  ['Mercedes Benz', 'C500', 'red'],
  ['BMW', 'M5', 'red'],
  ['BMW', 'X6', 'white'],
]);
factory.listFlyweights(); // 享元工厂: 我有5个享元:
// Chevrolet-Camaro2018-pink
// Mercedes Benz-C300-black
// Mercedes Benz-C500-red
// BMW-M5-red
// BMW-X6-white
function addCarToPoliceDatabase(
  ff: FlyweightFactory, plates: string, owner: string,
  brand: string, model: string, color: string,
) {
  const flyweight = ff.getFlyweight([brand, model, color]);
  flyweight.operation([plates, owner]);
}


addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'M5', 'red'); 
// 享元工厂: 找到了已存在的享元.
// 享元: 共享 (['BMW', 'M5', 'red']), 独有 (['CL234IR', 'James Doe']).
addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'X1', 'red');
// 享元工厂: 不能够寻找到享元,创建一个新的
// 享元: 共享 (['BMW', 'X1', 'red']), 独有 (['CL234IR', 'James Doe']) state.
factory.listFlyweights(); // 享元工厂: 我有6个享元:
// Chevrolet-Camaro2018-pink
// Mercedes Benz-C300-black
// Mercedes Benz-C500-red
// BMW-M5-red
// BMW-X6-white
// BMW-X1-red

简单来说,享元模式通过共享多个对象的部分状态来实现上述功能,享元会将不同对象的相同数据进行缓存以节省内存。如同上述例子中,车的型号会被存储在享元中,车的主人是独享的。当将一个 主人-车辆 数据加入数据库中时,享元工厂先查找享元中是否已存在该型号车的数据,有的话直接返回,没有的话创建这个型号。

  行为型

行为模式负责对象间的高效沟通和职责委派。

  • 迭代器模式

迭代器模式是一种行为设计模式, 它能够在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。

举个现实的例子,假如去北京旅游,故宫、长城、天安门、颐和园、北大、清华是此次旅行的游览目标,可以将他们组成一个目的地集合。第一种游览方式是按照自己的意愿顺序去游玩,第二种方式是按照某些博主推荐的游览顺序游玩,第三种方式是报个旅行团,按照旅行团安排的顺序游玩。以上这三种选择就是目的地集合的迭代器。

迭代器模式结构:

8e246b51009d3ea7f97c601bf05d3d2d.png

代码示例:

interface Iterator<T> {
    current(): T; // 返回当前的元素
    next(): T; // 返回下一个元素
    key(): number; // 返回当前元素的key
    valid(): boolean; // 检测当前位置是否是有效的
    rewind(): void; // 将迭代器回退到第一个元素
}
interface Aggregator {
    getIterator(): Iterator<string>; // 获取外部迭代器
}
// 具体迭代器实现各种遍历算法。这些类在任何时候都存储当前遍历位置
class AlphabeticalOrderIterator implements Iterator<string> {
    private collection: WordsCollection;
    private position: number = 0;
    private reverse: boolean = false;
    constructor(collection: WordsCollection, reverse: boolean = false) {
        this.collection = collection;
        this.reverse = reverse;
        if (reverse) {
            this.position = collection.getCount() - 1;
        }
    }
    public rewind() {
        this.position = this.reverse ?
            this.collection.getCount() - 1 :
            0;
    }
    public current(): string {
        return this.collection.getItems()[this.position];
    }
    public key(): number {
        return this.position;
    }
    public next(): string {
        const item = this.collection.getItems()[this.position];
        this.position += this.reverse ? -1 : 1;
        return item;
    }
    public valid(): boolean {
        if (this.reverse) {
            return this.position >= 0;
        }
        return this.position < this.collection.getCount();
    }
}
// 具体集合提供一个或多个方法来检索新的迭代器实例,与集合类兼容。
class WordsCollection implements Aggregator {
    private items: string[] = [];
    public getItems(): string[] {
        return this.items;
    }
    public getCount(): number {
        return this.items.length;
    }
    public addItem(item: string): void {
        this.items.push(item);
    }
    public getIterator(): Iterator<string> {
        return new AlphabeticalOrderIterator(this);
    }
    public getReverseIterator(): Iterator<string> {
        return new AlphabeticalOrderIterator(this, true);
    }
}
// 客户端代码
const collection = new WordsCollection();
collection.addItem('First');
collection.addItem('Second');
collection.addItem('Third');
const iterator = collection.getIterator();
console.log('Straight traversal:');
while (iterator.valid()) {
    console.log(iterator.next()); // First Second Third
}
const reverseIterator = collection.getReverseIterator();
while (reverseIterator.valid()) {
    console.log(reverseIterator.next()); // Third Second First
}

最简单的理解方式的话,其实就是我们常说的ES6中的迭代器。

  • 解释器模式

解释器模式是一种行为设计模式。给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。

代码示例:

class Context {
  constructor() {
    this._list = []; // 存放 终结符表达式
    this._sum = 0; // 存放 非终结符表达式(运算结果)
  }
  get sum() {
    return this._sum;
  }
  set sum(newValue) {
    this._sum = newValue;
  }
  add(expression) {
    this._list.push(expression);
  }
  get list() {
    return [...this._list];
  }
}
class PlusExpression {
  interpret(context) {
    if (!(context instanceof Context)) {
      throw new Error("TypeError");
    }
    context.sum = ++context.sum;
  }
}
class MinusExpression {
  interpret(context) {
    if (!(context instanceof Context)) {
      throw new Error("TypeError");
    }
    context.sum = --context.sum;
  }
}
// 客户端代码
const context = new Context();
// 添加加法表达式
context.add(new PlusExpression()); 
// 添加加法表达式
context.add(new PlusExpression());
// 添加减法表达式
context.add(new MinusExpression());
// 依次执行: 加法、加法、减法表达式
context.list.forEach(expression => expression.interpret(context));
console.log(context.sum); // 1
  • 观察者模式

观察者模式是一种行为设计模式,又被称为发布订阅模式。它允许定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。

举个现实的例子,比如你订阅了人民日报,每当它发版的时候,都会有邮递员将报纸送到你手中,而不需要你跑去报刊亭自己购买。出版社为发布者,你为订阅者,出版社维护着一份订阅者的名单,当你不想再订阅时可以申请退出订阅。

观察者模式结构:

c04b441d2b33f672bacd26945383f5b5.png

代码示例:

interface Subject { // 声明了一组管理订阅者的方法
    attach(observer: Observer): void; // 为订阅者附加观察者
    detach(observer: Observer): void; // 从订阅者身上剥离观察者
    notify(): void; // 通知所有观察者的方法
}
// 具体订阅者
class ConcreteSubject implements Subject { 
    public state: number;
    private observers: Observer[] = [];
    public attach(observer: Observer): void {
        const isExist = this.observers.includes(observer);
        if (isExist) {
            return console.log('Subject: Observer has been attached already.');
        }
        console.log('Subject: Attached an observer.');
        this.observers.push(observer);
    }
    public detach(observer: Observer): void {
        const observerIndex = this.observers.indexOf(observer);
        if (observerIndex === -1) {
            return console.log('Subject: Nonexistent observer.');
        }
        this.observers.splice(observerIndex, 1);
        console.log('Subject: Detached an observer.');
    }
    // 触发每个订阅者更新
    public notify(): void {
        console.log('Subject: Notifying observers...');
        for (const observer of this.observers) {
            observer.update(this);
        }
    }
    // 业务逻辑等,当其发生变化时,触发notify方法
    public someBusinessLogic(): void {
        console.log('\nSubject: I\'m doing something important.');
        this.state = Math.floor(Math.random() * (10 + 1));
        console.log(`Subject: My state has just changed to: ${this.state}`);
        this.notify();
    }
}
interface Observer { // 声明更新方法,由订阅者调用
    // Receive update from subject.
    update(subject: Subject): void;
}
// 具体观察者
class ConcreteObserverA implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof ConcreteSubject && subject.state < 3) {
            console.log('ConcreteObserverA: Reacted to the event.');
        }
    }
}
class ConcreteObserverB implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof ConcreteSubject && (subject.state === 0 || subject.state >= 2)) {
            console.log('ConcreteObserverB: Reacted to the event.');
        }
    }
}
// 客户端代码
const subject = new ConcreteSubject();
const observer1 = new ConcreteObserverA();
subject.attach(observer1); // Subject: Attached an observer.
const observer2 = new ConcreteObserverB();
subject.attach(observer2); // Subject: Attached an observer.
subject.someBusinessLogic(); // Subject: I'm doing something important. Subject: My state has just changed to: 6.  Subject: Notifying observers...  ConcreteObserverB: Reacted to the event.    
subject.someBusinessLogic(); // Subject: I'm doing something important. Subject: My state has just changed to: 1.  Subject: Notifying observers... ConcreteObserverA: Reacted to the event.  
subject.detach(observer2); // Subject: Detached an observer.
subject.someBusinessLogic(); // Subject: I'm doing something important. Subject: My state has just changed to: 5. Subject: Notifying observers...
  • 中介者模式

中介者模式是一种行为设计模式, 能够减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。

举个现实的例子,航班与航班之间不会直接沟通,而是与塔台沟通,从而可来避免航线交叉、重复而可能引起的飞机之间的碰撞。当然现实中还有很多其他的例子,中介者模式其实就是我们字面上理解的中介者的意思。

中介者模式结构:

1096e56d30691193fc929085f9c89de3.png

代码示例:

interface Mediator {
    notify(sender: object, event: string): void;
}
class ConcreteMediator implements Mediator {
    private component1: Component1;
    private component2: Component2;
    constructor(c1: Component1, c2: Component2) {
        this.component1 = c1;
        this.component1.setMediator(this);
        this.component2 = c2;
        this.component2.setMediator(this);
    }
    public notify(sender: object, event: string): void {
        if (event === 'A') {
            console.log('Mediator reacts on A and triggers following operations:');
            this.component2.doC();
        }
        if (event === 'D') {
            console.log('Mediator reacts on D and triggers following operations:');
            this.component1.doB();
            this.component2.doC();
        }
    }
}
class BaseComponent {
    protected mediator: Mediator;


    constructor(mediator?: Mediator) {
        this.mediator = mediator!;
    }


    public setMediator(mediator: Mediator): void {
        this.mediator = mediator;
    }
}
class Component1 extends BaseComponent {
    public doA(): void {
        console.log('Component 1 does A.');
        this.mediator.notify(this, 'A');
    }


    public doB(): void {
        console.log('Component 1 does B.');
        this.mediator.notify(this, 'B');
    }
}
class Component2 extends BaseComponent {
    public doC(): void {
        console.log('Component 2 does C.');
        this.mediator.notify(this, 'C');
    }


    public doD(): void {
        console.log('Component 2 does D.');
        this.mediator.notify(this, 'D');
    }
}
// 客户端代码
const c1 = new Component1();
const c2 = new Component2();
const mediator = new ConcreteMediator(c1, c2);
// 触发操作A
c1.doA(); // Component 1 does A. Mediator reacts on A and triggers following operations: Component 2 does C.
// 触发操作B 
c2.doD(); // Component 2 does D. Mediator reacts on D and triggers following operations: Component 1 does B. Component 2 does C.

程序组件通过特殊的中介者对象进行间接沟通, 达到了减少组件之间依赖关系的目的。

  • 访问者模式

访问者模式是一种行为设计模式, 它能将算法与其所作用的对象隔离开来。

举个现实的例子,一个房地产销售人员,他可以向各种各样的人推销,如果面对富豪,他推销别墅,如果面对高收入人群,他推销普大平层,如果面对普通收入人群,他推销普通高层。

访问者模式结构:

e4b312dd9307876cfe6cc38e096f190d.png

代码示例:

interface Component {
    accept(visitor: Visitor): void;
}
class ConcreteComponentA implements Component {
    public accept(visitor: Visitor): void {
        visitor.visitConcreteComponentA(this);
    }
    public exclusiveMethodOfConcreteComponentA(): string {
        return 'A';
    }
}
class ConcreteComponentB implements Component {
    public accept(visitor: Visitor): void {
        visitor.visitConcreteComponentB(this);
    }
    public specialMethodOfConcreteComponentB(): string {
        return 'B';
    }
}
interface Visitor {
    visitConcreteComponentA(element: ConcreteComponentA): void;


    visitConcreteComponentB(element: ConcreteComponentB): void;
}
class ConcreteVisitor1 implements Visitor {
    public visitConcreteComponentA(element: ConcreteComponentA): void {
        console.log(`${element.exclusiveMethodOfConcreteComponentA()} + ConcreteVisitor1`);
    }
    public visitConcreteComponentB(element: ConcreteComponentB): void {
        console.log(`${element.specialMethodOfConcreteComponentB()} + ConcreteVisitor1`);
    }
}
class ConcreteVisitor2 implements Visitor {
    public visitConcreteComponentA(element: ConcreteComponentA): void {
        console.log(`${element.exclusiveMethodOfConcreteComponentA()} + ConcreteVisitor2`);
    }
    public visitConcreteComponentB(element: ConcreteComponentB): void {
        console.log(`${element.specialMethodOfConcreteComponentB()} + ConcreteVisitor2`);
    }
}
// 客户端代码
function clientCode(components: Component[], visitor: Visitor) {
    // ...
    for (const component of components) {
        component.accept(visitor);
    }
    // ...
}
const components = [
    new ConcreteComponentA(),
    new ConcreteComponentB(),
];
// 通过基础访问者接口,客户端代码与所有的访问者一同工作
const visitor1 = new ConcreteVisitor1();
clientCode(components, visitor1); // A + ConcreteVisitor1 B + ConcreteVisitor1
// 同样的客户端代码可以与不同类型的访问者一同工作
const visitor2 = new ConcreteVisitor2();
clientCode(components, visitor2); // A + ConcreteVisitor2 B + ConcreteVisitor2
  • 状态模式

状态模式是一种行为设计模式, 可以在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。

举个实际的例子,你的手机,有话费状态,可以打电话,无话费状态,不可以打电话。设计上就是不同的状态下所对应的功能不同。

状态模式结构:

430d63759429638c00b68bb8e438e3c8.png

代码示例:

class Context {
    private state: State;
    constructor(state: State) {
        this.transitionTo(state);
    }
    public transitionTo(state: State): void {
        console.log(`Context: Transition to ${(<any>state).constructor.name}.`);
        this.state = state;
        this.state.setContext(this);
    }
    public request1(): void {
        this.state.handle1();
    }
    public request2(): void {
        this.state.handle2();
    }
}
abstract class State {
    protected context: Context;


    public setContext(context: Context) {
        this.context = context;
    }


    public abstract handle1(): void;


    public abstract handle2(): void;
}
class ConcreteStateA extends State {
    public handle1(): void {
        console.log('ConcreteStateA handles request1.');
        console.log('ConcreteStateA wants to change the state of the context.');
        this.context.transitionTo(new ConcreteStateB());
    }
    public handle2(): void {
        console.log('ConcreteStateA handles request2.');
    }
}
class ConcreteStateB extends State {
    public handle1(): void {
        console.log('ConcreteStateB handles request1.');
    }
    public handle2(): void {
        console.log('ConcreteStateB handles request2.');
        console.log('ConcreteStateB wants to change the state of the context.');
        this.context.transitionTo(new ConcreteStateA());
    }
}
// 客户端代码
const context = new Context(new ConcreteStateA());
context.request1(); // Context: Transition to ConcreteStateA. ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context.
context.request2(); // Context: Transition to ConcreteStateB. ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context. Context: Transition to ConcreteStateA.
  • 备忘录模式

备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态,允许生成对象状态的快照并在以后将其还原,它不会影响它所处理的对象的内部结构, 也不会影响快照中保存的数据。

备忘录模式结构:

9a15bf403a6553d0368edd443b82bdcd.png

代码示例:

class Originator {
    private state: string;
    constructor(state: string) {
        this.state = state;
        console.log(`Originator: My initial state is: ${state}`);
    }
    public doSomething(): void {
        console.log('Originator: I\'m doing something important.');
        this.state = this.generateRandomString(30);
        console.log(`Originator: and my state has changed to: ${this.state}`);
    }
    private generateRandomString(length: number = 10): string {
        const charSet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        return Array
            .apply(null, { length })
            .map(() => charSet.charAt(Math.floor(Math.random() * charSet.length)))
            .join('');
    }
    public save(): Memento {
        return new ConcreteMemento(this.state);
    }
    public restore(memento: Memento): void {
        this.state = memento.getState();
        console.log(`Originator: My state has changed to: ${this.state}`);
    }
}
interface Memento {
    getState(): string;
    getName(): string;
    getDate(): string;
}
class ConcreteMemento implements Memento {
    private state: string;
    private date: string;
    constructor(state: string) {
        this.state = state;
        this.date = new Date().toISOString().slice(0, 19).replace('T', ' ');
    }
    public getState(): string {
        return this.state;
    }
    public getName(): string {
        return `${this.date} / (${this.state.substr(0, 9)}...)`;
    }
    public getDate(): string {
        return this.date;
    }
}
class Caretaker {
    private mementos: Memento[] = [];
    private originator: Originator;
    constructor(originator: Originator) {
        this.originator = originator;
    }
    public backup(): void {
        console.log('\nCaretaker: Saving Originator\'s state...');
        this.mementos.push(this.originator.save());
    }
    public undo(): void {
        if (!this.mementos.length) {
            return;
        }
        const memento = this.mementos.pop();
        console.log(`Caretaker: Restoring state to: ${memento.getName()}`);
        this.originator.restore(memento);
    }
    public showHistory(): void {
        console.log('Caretaker: Here\'s the list of mementos:');
        for (const memento of this.mementos) {
            console.log(memento.getName());
        }
    }
}
// 客户端代码
const originator = new Originator('Super-duper-super-puper-super.');
const caretaker = new Caretaker(originator);


caretaker.backup();
originator.doSomething();


caretaker.backup();
originator.doSomething();


caretaker.backup();
originator.doSomething();


console.log('');
caretaker.showHistory();


console.log('\nClient: Now, let\'s rollback!\n');
caretaker.undo();


console.log('\nClient: Once more!\n');
caretaker.undo();
Originator: My initial state is: Super-duper-super-puper-super.


Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: qXqxgTcLSCeLYdcgElOghOFhPGfMxo


Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: iaVCJVryJwWwbipieensfodeMSWvUY


Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: oSUxsOCiZEnohBMQEjwnPWJLGnwGmy


Caretaker: Here's the list of mementos:
2019-02-17 15:14:05 / (Super-dup...)
2019-02-17 15:14:05 / (qXqxgTcLS...)
2019-02-17 15:14:05 / (iaVCJVryJ...)


Client: Now, let's rollback!


Caretaker: Restoring state to: 2019-02-17 15:14:05 / (iaVCJVryJ...)
Originator: My state has changed to: iaVCJVryJwWwbipieensfodeMSWvUY


Client: Once more!


Caretaker: Restoring state to: 2019-02-17 15:14:05 / (qXqxgTcLS...)
Originator: My state has changed to: qXqxgTcLSCeLYdcgElOghOFhPGfMxo
  • 策略模式

策略模式是一种行为设计模式, 能让定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。

举个现实的例子,比如赶火车,到达火车站的策略有公交车、地铁、出租车等,我们可以根据预算或时间等因素选择其中的一种策略。

策略模式结构:

a799668cae5ee511156c2a0828d5b0e2.png

代码示例:

class Context {
    private strategy: Strategy;
    constructor(strategy: Strategy) {
        this.strategy = strategy;
    }
    public setStrategy(strategy: Strategy) {
        this.strategy = strategy;
    }
    public doSomeBusinessLogic(): void {
        console.log('Context: Sorting data using the strategy (not sure how it\'ll do it)');
        const result = this.strategy.doAlgorithm(['a', 'b', 'c', 'd', 'e']);
        console.log(result.join(','));
    }
}
interface Strategy {
    doAlgorithm(data: string[]): string[];
}
class ConcreteStrategyA implements Strategy {
    public doAlgorithm(data: string[]): string[] {
        return data.sort();
    }
}
class ConcreteStrategyB implements Strategy {
    public doAlgorithm(data: string[]): string[] {
        return data.reverse();
    }
}
// 客户端代码
const context = new Context(new ConcreteStrategyA());
console.log('Client: Strategy is set to normal sorting.');
context.doSomeBusinessLogic();


console.log('');


console.log('Client: Strategy is set to reverse sorting.');
context.setStrategy(new ConcreteStrategyB());
context.doSomeBusinessLogic();
Client: Strategy is set to normal sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
a,b,c,d,e


Client: Strategy is set to reverse sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
e,d,c,b,a
  • 模板方法模式

模板方法模式是一种行为设计模式, 它在基类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。

举个现实的例子,农村自建房有一套固定的模版方法(比如为:打地基 -> 建造主体 -> 封顶 -> 铺设水电 -> 装修),但这其中可提供几个扩展点, 允许潜在的房屋业主调整成品房屋的部分细节,如装修风格,这使得成品房屋会有不同。

模版方法模式结构:

0464cf8b049b4caa3909241fc8f7f246.png

代码示例:

abstract class AbstractClass {
    public templateMethod(): void {
        this.baseOperation1();
        this.requiredOperations1();
        this.baseOperation2();
        this.hook1();
        this.requiredOperation2();
        this.baseOperation3();
        this.hook2();
    }
    protected baseOperation1(): void {
        console.log('AbstractClass says: I am doing the bulk of the work');
    }
    protected baseOperation2(): void {
        console.log('AbstractClass says: But I let subclasses override some operations');
    }
    protected baseOperation3(): void {
        console.log('AbstractClass says: But I am doing the bulk of the work anyway');
    }
    protected abstract requiredOperations1(): void;
    protected abstract requiredOperation2(): void;
    protected hook1(): void { }
    protected hook2(): void { }
}
class ConcreteClass1 extends AbstractClass {
    protected requiredOperations1(): void {
        console.log('ConcreteClass1 says: Implemented Operation1');
    }
    protected requiredOperation2(): void {
        console.log('ConcreteClass1 says: Implemented Operation2');
    }
}
class ConcreteClass2 extends AbstractClass {
    protected requiredOperations1(): void {
        console.log('ConcreteClass2 says: Implemented Operation1');
    }
    protected requiredOperation2(): void {
        console.log('ConcreteClass2 says: Implemented Operation2');
    }
    protected hook1(): void {
        console.log('ConcreteClass2 says: Overridden Hook1');
    }
}
// 客户端代码
function clientCode(abstractClass: AbstractClass) {
    // ...
    abstractClass.templateMethod();
    // ...
}


console.log('Same client code can work with different subclasses:');
clientCode(new ConcreteClass1());
console.log('');


console.log('Same client code can work with different subclasses:');
clientCode(new ConcreteClass2());
Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway


Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
  • 职责链模式

职责链模式是一种行为设计模式, 允许将请求沿着处理者链进行发送。收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

职责链模式结构:

b6b5290a5b3dd78bbd46c49c0400dd03.png

代码示例:

interface Handler {
    setNext(handler: Handler): Handler;


    handle(request: string): string;
}
abstract class AbstractHandler implements Handler
{
    private nextHandler: Handler;
    public setNext(handler: Handler): Handler {
        this.nextHandler = handler;
        return handler;
    }
    public handle(request: string): string {
        if (this.nextHandler) {
            return this.nextHandler.handle(request);
        }
        return null;
    }
}
class MonkeyHandler extends AbstractHandler {
    public handle(request: string): string {
        if (request === 'Banana') {
            return `Monkey: I'll eat the ${request}.`;
        }
        return super.handle(request);
    }
}
class SquirrelHandler extends AbstractHandler {
    public handle(request: string): string {
        if (request === 'Nut') {
            return `Squirrel: I'll eat the ${request}.`;
        }
        return super.handle(request);
    }
}
class DogHandler extends AbstractHandler {
    public handle(request: string): string {
        if (request === 'MeatBall') {
            return `Dog: I'll eat the ${request}.`;
        }
        return super.handle(request);
    }
}
function clientCode(handler: Handler) {
    const foods = ['Nut', 'Banana', 'Cup of coffee'];
    for (const food of foods) {
        console.log(`Client: Who wants a ${food}?`);
        const result = handler.handle(food);
        if (result) {
            console.log(`  ${result}`);
        } else {
            console.log(`  ${food} was left untouched.`);
        }
    }
}
// 客户端代码
const monkey = new MonkeyHandler();
const squirrel = new SquirrelHandler();
const dog = new DogHandler();


monkey.setNext(squirrel).setNext(dog);


console.log('Chain: Monkey > Squirrel > Dog\n');
clientCode(monkey);
console.log('');


console.log('Subchain: Squirrel > Dog\n');
clientCode(squirrel);
Chain: Monkey > Squirrel > Dog


Client: Who wants a Nut?
  Squirrel: I'll eat the Nut.
Client: Who wants a Banana?
  Monkey: I'll eat the Banana.
Client: Who wants a Cup of coffee?
  Cup of coffee was left untouched.


Subchain: Squirrel > Dog


Client: Who wants a Nut?
  Squirrel: I'll eat the Nut.
Client: Who wants a Banana?
  Banana was left untouched.
Client: Who wants a Cup of coffee?
  Cup of coffee was left untouched.
  • 命令模式

命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象。该转换能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。

命令模式结构:

3bf576886e0b8aba2a0a0ea9bbfea5c7.png

代码示例:

interface Command {
    execute(): void;
}
class SimpleCommand implements Command {
    private payload: string;
    constructor(payload: string) {
        this.payload = payload;
    }
    public execute(): void {
        console.log(`SimpleCommand: See, I can do simple things like printing (${this.payload})`);
    }
}
class ComplexCommand implements Command {
    private receiver: Receiver;
    private a: string;
    private b: string;
    constructor(receiver: Receiver, a: string, b: string) {
        this.receiver = receiver;
        this.a = a;
        this.b = b;
    }
    public execute(): void {
        console.log('ComplexCommand: Complex stuff should be done by a receiver object.');
        this.receiver.doSomething(this.a);
        this.receiver.doSomethingElse(this.b);
    }
}
class Receiver {
    public doSomething(a: string): void {
        console.log(`Receiver: Working on (${a}.)`);
    }
    public doSomethingElse(b: string): void {
        console.log(`Receiver: Also working on (${b}.)`);
    }
}
class Invoker {
    private onStart: Command;
    private onFinish: Command;
    public setOnStart(command: Command): void {
        this.onStart = command;
    }
    public setOnFinish(command: Command): void {
        this.onFinish = command;
    }
    public doSomethingImportant(): void {
        console.log('Invoker: Does anybody want something done before I begin?');
        if (this.isCommand(this.onStart)) {
            this.onStart.execute();
        }
        console.log('Invoker: ...doing something really important...');
        console.log('Invoker: Does anybody want something done after I finish?');
        if (this.isCommand(this.onFinish)) {
            this.onFinish.execute();
        }
    }
    private isCommand(object): object is Command {
        return object.execute !== undefined;
    }
}
// 客户端代码
const invoker = new Invoker();
invoker.setOnStart(new SimpleCommand('Say Hi!'));
const receiver = new Receiver();
invoker.setOnFinish(new ComplexCommand(receiver, 'Send email', 'Save report'));


invoker.doSomethingImportant();
Invoker: Does anybody want something done before I begin?
SimpleCommand: See, I can do simple things like printing (Say Hi!)
Invoker: ...doing something really important...
Invoker: Does anybody want something done after I finish?
ComplexCommand: Complex stuff should be done by a receiver object.
Receiver: Working on (Send email.)
Receiver: Also working on (Save report.)

5e500b180ff8326978e330c5c1574221.png

参考文献

Alexander Shvets, Dive-into Design Patterns[M], Finelybook, 2019.

70ceb186725598c03aa268fe0518c5d4.png

团队介绍

我们是大淘宝技术-营销与平台策略技术-营销产品团队,主要负责淘宝好价、百亿补贴、聚划算、天天特卖等大淘宝核心产品及各类大型的营销会场活动,同时我们也是前端智能化的先锋队,有方舟、千帆、imgcook、智能UI等多种技术产品。

¤ 拓展阅读 ¤

3DXR技术 | 终端技术 | 音视频技术

服务端技术 | 技术质量 | 数据算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python 算法基础篇之字符串操作:索引、切片、常用方法

Python 算法基础篇之字符串操作&#xff1a;索引、切片、常用方法 引言 1. 字符串的概念和创建2. 字符串的索引3. 字符串的切片4. 字符串的常用方法 a ) 查找子字符串 b ) 替换子字符串 c ) 拆分和连接字符串 总结 引言 字符串是一种常见的数据类型&#xff0c;在 Python 中对…

又整新活,新版 IntelliJ IDEA 有点东西!

作为一个经常使用IntelliJ IDEA来写代码的老用户&#xff0c;每次对于JetBrains软件的更新都是非常关注的。 这不最近这段时间&#xff0c;JetBrains连发了多个软件的EAP版本&#xff1a; 同时JetBrains的官博中也宣布了一个重要的新特性&#xff0c;那就是&#xff1a; 在所…

X.509数字证书的基本原理

一、前言 数字证书是现代互联网中个体间相互信任的基石。 如果没有了数字证书&#xff0c;那么也就没有了各式各样的电商平台以及方便的电子支付服务。 数字证书是网络安全中的一个非常重要组成部分。如果要学好网络安全&#xff0c;那么必须充分理解它的原理。 目前我们所…

keepalived 实现双机热备

文章目录 一、说明二、概念解释三、环境准备四、操作过程五、验证 一、说明 我们经常听说 nginx keepalived 双机热备&#xff0c;其实在这里&#xff0c;双机热备只是利用 keepalived 实现两个节点的故障切换&#xff0c;当主节点挂了&#xff0c;备用节点顶上&#xff0c;保…

深入浅出关于网易邮箱开启smtp服务教程

各平台邮箱开启SMTP服务教程 一、QQ邮箱 &#xff08;服务器地址&#xff1a;smtp.qq.com&#xff09; 第一步&#xff1a;复制https://mail.qq.com/ 登录QQ邮箱后电击左上角设置&#xff0c;如图&#xff1a; 第二步&#xff1a;点击进入“帐户”页面 &#xff0c;如图&…

CodeLocator简单使用(AndroidStudio中点击布局元素确认对应view信息)快速接手陌生项目利器

对于陌生项目的一些改动或重构需求时&#xff0c;如果可以在APP点点就能确定知道当前管理哪个activity或fragment必然是省去了很多去代码里搜来搜去的时间。在社群讨论中发现这款AS插件:CodeLocator ,虽然有2年没更新了 今天也试一试看看是否有帮助。 首先下载最新版本的插件&…

通过OSG实现对模型的日照模拟

1. 加载模型 通过OpenSceneGraph加载一个倾斜摄影的场景模型数据&#xff1a; #include <iostream> #include <Windows.h>#include <osgViewer/Viewer> #include <osgDB/ReadFile>using namespace std;int main() {string osgPath "D:/Data/Da…

Appium自动化测试知识点

一、App环境搭建 1、安装jdk&#xff0c;配置jdk环境变量 2、Android SDK环境安装 3、Appium server安装 4、模拟器的安装&#xff08;夜神模拟器&#xff09; 5、安装appium-python-client Python第三方库 二、App自动化测试原理 如何通过代码操作不同操作系统&#xff08;…

基于Dubbo分布式网上售票系统

一、项目介绍 民航售票是一个高度依赖信息业的行业。但在机票销售的管理和规范这方面上存在着很多各种各样的问题。例如订票是客运行业中的一个最基本的业务,表面上看,它只是机票站业务的一个简单的部分,但是它涉及到管理与客户服务等多方面,关系到民航公司能否正常运作。…

log4j--动态打印日志文件到指定文件夹

文章目录 log4j--动态打印日志文件到指定文件夹1、添加Maven依赖2、配置文件 log4j.properties3、编写日志打印工具类 LogUtil4、工具类调用 log4j–动态打印日志文件到指定文件夹 1、添加Maven依赖 <!-- log4j日志相关坐标 --><dependency><groupId>org.s…

无虚拟 DOM 版 Vue 进行到哪一步了?

前言 就在一年前的 Vue Conf 2022&#xff0c;尤雨溪向大家分享了一个非常令人期待的新模式&#xff1a;无虚拟 DOM 模式&#xff01; 我看了回放之后非常兴奋&#xff0c;感觉这是个非常牛逼的新 feature&#xff0c;鉴于可能会有部分人还不知道或者还没听过什么是 Vue 无虚…

哈佛“聘请”AI担任导师,主讲教授:别全信它的,学生应“批判性地思考”

就在人们为AI聊天机器人的利弊争论不休时&#xff0c;哈佛宣布了一个重磅决定&#xff1a;将利用类似ChatGPT的聊天机器人来帮助授课了。 负责的还是计算机系的旗舰项目 —— 计算机科学导论&#xff0c;也就是著名的 CS50。借助机器人导师&#xff0c;哈佛的 CS50 项目将拥有…

Python、Selenium实现问卷星自动填写(内含适配个人问卷的方法)

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 &#x1f4d6;所属专栏&#xff1a;Py…

有哪些好用的远程传输大文件的软件

随着网络技术的日益进步和普及&#xff0c;大文件远程传输已经成为了人们生活和工作中必不可少的一部分。然而&#xff0c;在远程传输大文件的过程中&#xff0c;经常会遇到传输速度慢、容易受到干扰等问题&#xff0c;因此需要一款高效、稳定、安全的大文件远程传输软件来解决…

CCF真题练习:202209-1如此编码

题目背景 某次测验后&#xff0c;顿顿老师在黑板上留下了一串数字 23333 便飘然而去。凝望着这个神秘数字&#xff0c;小 P 同学不禁陷入了沉思…… 题目描述 已知某次测验包含 n 道单项选择题&#xff0c;其中第 i 题&#xff08;1≤i≤n&#xff09;有 个选项&#xff0c;…

【Vue 面试题10道】我好像之前想过要写,不过之前JavaScript面试题比较多,就暂时略过了,这些应该几乎把常问的都包括了

博主&#xff1a;_LJaXi Or 東方幻想郷 专栏&#xff1a; 前端面试题 开发工具&#xff1a;Vs Code 本题针对 Vue2 这些几乎把常用的都包括了&#xff0c;问别的就没意思了&#xff0c;毕竟工作拧螺丝嘛 我都好久不用Vue了&#xff0c;不过用了React再回看Vue感觉好简单啊… 其…

数据库性能优化中的查询优化

数据库性能优化中的查询优化 概述 在数据库应用中&#xff0c;查询操作是最常见的操作之一。查询优化是数据库性能优化的关键一环&#xff0c;通过对查询语句和查询执行计划的优化&#xff0c;可以显著提高数据库系统的性能和效率。本文将介绍查询优化的相关知识&#xff0c;…

结构型模式 - 代理模式

概述 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时&#xff0c;访问对象不适合或者不能直接引用目标对象&#xff0c;代理对象作为访问对象和目标对象之间的中介。 Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期…

Docker 基础知识解析:容器与传统虚拟化对比:资源利用、启动时间、隔离性和部署效率

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Vscode配置grpc+c#+proto

首先是环境配置&#xff0c;用的dotnet5.0的sdk&#xff0c;所以Vscode的C#插件版本要选择1.24&#xff0c;然后需要配置C# Snippets、NuGget Package Manager、vscode-proto3、vscode-solution-extension&#xff08;可选&#xff09;。 以vscode-solution-extension为例新建A…