ts实现的23种设计模式和设计原则

3,322 阅读18分钟

无论是设计模式还是设计原则,都是针对面向对象编程,其他编程范式并不很适合,编程范式参考这篇文章。 相关实现会使用typescript,如果对ts不熟,请参考这篇文章


设计模式

这里参考 Design Patterns:elements of reusable object-oriented software

什么是设计模式

设计模式的定义是由一个建筑模式的概念引出的:

Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice

和建筑模式类似,面向对象设计模式是为我们日常开发中重复发生的问题总结出来的一套主要解决方案。

分类

设计模式分为三类,它们分别是

  • Creational(创建)
    1. factory method 子类决定实例化哪个类,或者根据参数实例化不同对象
    2. prototype 通过复制一个原型创建新对象
    3. abstract factory生成工厂的工厂,其方法返回一个工厂类,可以在实现时返回具体的对象
    4. builder 将对象初始化和后续过程分开,初始化和不同的后续过程组合可以创建出不同对象
    5. singleton 全局只有一个实例
  • Structural(结构)
    1. adapter 让两个不兼容接口一起使用 ,比如target调用request方法,Adaptee只有specialRequest方法,需要提供一个Adapter提供一个request方法帮助调用specialRequest
    2. proxy 两者接口一样,引入中间者而不直接操作原对象
    3. bridge 将接口和实现分离,将接口中对实现的约束指向另一个接口
    4. decorator 和bridge类似,但只是对当前已有功能的增强,
    5. composite 结构类似一棵树,可以递归调用每个结点
    6. facade 为一个系统提供统一的接口
    7. flyweight 利用缓存实现对象共享
  • Behavioral(行为)
    1. chain of responsibility 将处理对象组成一个链表,如果当前对象可以处理则处理否则传给下一个
    2. ommand
    3. interpreter
    4. iterator
    5. mediator 用一个对象封装多个对象的交互,实现低耦合
    6. memento 在外部保存内部状态,比如备份
    7. observer 一对多的依赖关系,当被依赖对象变化时,其他都会被通知
    8. state 对象的行为根据状态改变而改变
    9. strategy 封装一系列可以互相替换的策略
    10. template Method 抽象方法中包含默认步骤和默认方法,具体类实现时可以修改某些步骤
    11. visitor

描述每一种设计模式

我们在讲每种设计模式时会按照这样的格式来讲,方便对每种模式有更清晰的认识。

  1. 描述:直接引用书中的intent部分,从原始的描述中理解设计模式;
  2. 解释:包含对描述的解读,和结构图
  3. 实现:对实现进行适当标注,并给出具体代码实现(结构图是书上的原图,具体实现会有部分差异)。

Creational Patterns(创建模式)

用于对象创建,并将创建的逻辑进行封装,对外界只暴露必要的api,从而增加具体实现的灵活性。

1. factory method (工厂方法)

  1. 描述:

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

  1. 解释:定义一个类Creator包含一个抽象工厂方法,其子类来决定实例化哪个类。
    结构如下

  2. 实现: Product 定义工厂方法创建的对象接口
    ConcreteProduct 实现Product的接口
    Creator 声明工厂方法
    ConcreteCreator 实现工厂方法,用来实例化ConcreteProduct 1)先按上面的结构进行实现

abstract class Product {
  abstract say():void;
}
class ConcreteProduct extends Product {
  say() {
    console.log("emmmm");
  }
}
abstract class Creator {
  abstract factorMethod():Product;
  someOperation() {
    const product = this.factorMethod();
    product.say();
  }
}
class ConcreteCreator extends Creator {
  factorMethod() {
    return new ConcreteProduct();
  }
}
new ConcreteCreator().someOperation()

2)工厂方法有个明显的问题就是每次实例化一个新的Product子类,都要创建一个Creator的子类,这里做一下改进,即Creator本身可以可以提供一个默认的factorMethod方法的,还可以通过创建子类进行扩展。 3)工厂方法的另一种变体是参数化工厂方法,Creator类直接根据参数实例化不同class并返回

class Creator {
  factorMethod(type: "a" | "b") {
    if (type === "a") {
      //实例化某个子类并返回
    }
    if (type === "b") {
      // 实例化另一个子类并返回
    }
    throw "no correct type";
  }
}
//new Creator().factorMethod('a').someOperation()

2. prototype(原型)

  1. 描述:

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

  1. 解释:指定一个实例对象做原型,然后通过复制这个对象创建一个新对象。
    关于这个模式不同语言有不同的实现方法,书上的实现方式是基于c++这种类不是对象的前提下进行的,在ts中,基于原型的继承机制天生的就有prototype,因此可以直接使用。

  2. 实现,借助Object.create()方法可以直接指定一个原型,并可以通过参数对原型的属性进行重写或者添加。注意如果没对原型上的属性进行重写,当原型上的属性变化时会影响继承对象上的属性。

var vehiclePrototype = {
  name: "aaaaa",
  getName: function () {
    console.log("name是:" + this.name);
  },
};

var vehicle = Object.create(vehiclePrototype, {
  name: {
    value: "bbbbb",
  },
});
console.log(vehicle.getName());
console.log(vehiclePrototype.getName());

3. abstract factory(抽象工厂)

  1. 描述:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

  1. 解释:提供一个创建相似或相互依赖对象的接口,即生产一系列工厂,用于生产多个系列的对象。 结构如下:
  2. 实现:
    AbstractFactory是个抽象类,包含两个抽象方法。
    ConcreFactory即工厂方法模式中的ConcreteCreator,其包含工厂方法
    AbtractProduct即工厂方法模式中的Product,具体实现如下
//生成用于实例化的class
interface AbstractProductA {
  usefulFunctionA(): string;
}

class ConcreteProductA1 implements AbstractProductA {
  public usefulFunctionA(): string {
    return "The result of the product A1.";
  }
}
class ConcreteProductA2 implements AbstractProductA {
  public usefulFunctionA(): string {
    return "The result of the product A2.";
  }
}
interface AbstractProductB {
  usefulFunctionB(): string;
}
class ConcreteProductB1 implements AbstractProductB {
  public usefulFunctionB(): string {
    return "The result of the product B1.";
  }
}
class ConcreteProductB2 implements AbstractProductB {
  public usefulFunctionB(): string {
    return "The result of the product B2.";
  }
}
//生成工厂的工厂
interface AbstractFactory {
  createProductA(): AbstractProductA;
  createProductB(): AbstractProductB;
}
//生成的工厂1,分别实例化产品系列1
class ConcreteFactory1 implements AbstractFactory {
  public createProductA(): AbstractProductA {
    return new ConcreteProductA1();
  }

  public createProductB(): AbstractProductB {
    return new ConcreteProductB1();
  }
}
//生成的工厂2,分别实例化产品系列2
class ConcreteFactory2 implements AbstractFactory {
  public createProductA(): AbstractProductA {
    return new ConcreteProductA2();
  }

  public createProductB(): AbstractProductB {
    return new ConcreteProductB2();
  }
}
//此时可以分别对两工厂进行实例化后调用工厂函数进行使用,比如
console.log(new ConcreteFactory1().createProductA().usefulFunctionA());

4. builder(建造者)

  1. 描述:

Separate the construction of a complex object from its representation so that the same construction process can create different representations.

  1. 解释:将一个对象的初始化和后续步骤分开,通过将初始化和不同的后续步骤结合可以创建出不同的结果。
    结构如下
  2. 实现:
    Director 构造一个使用buidler接口的对象
    Builder 为创建Product对象的各个部分指定抽象接口
    ConcreteBuilder 实现builder的接口并提供一个获取实现结果的方法 Product 最终生成的产品
interface Builder {
  buildPart: (brick: number) => void;
}
class ConcreteBuilder implements Builder {
  constructor(public product: Director) {}
  buildPart(brick: number) {
    this.product.partArr.push(brick);
    return this;
  }
  getResult() {
    return this.product.partArr;
  }
}
class Director {
  partArr: number[] = [];
  reset() {
    this.partArr = [];
  }
}

let builder = new ConcreteBuilder(new Director());
console.log(builder.buildPart(1).getResult());
console.log(builder.buildPart(3).getResult());

5. singleton(单例)

  1. 描述:

Ensure a class only has one instance, and provide a global point of access to it.

  1. 解释:确保一个class只有一个实例提供给全局访问。
    结构如下:
  2. 实现:
class Singleton {
  private static instance: Singleton;
  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }

    return Singleton.instance;
  }
}
var s1 = Singleton.getInstance();
var s2 = Singleton.getInstance();
console.log(s1 === s2);

Structural Patterns(结构型模式)

用于组合类与对象

1. adapter(适配器)

  1. 描述:

Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

  1. 解释:让两个不兼容的接口可以一起工作
    结构如下:
  2. 实现:
    Client 调用request方法
    Target 定义了client调用的接口
    Adaptee 现存接口,需要适配 Adapter 对Adaptee和接口Target进行适配
interface Target {
  request: () => void;
}

class Client {
  doSomeThing(instance: Target) {
    instance.request();
  }
}
class Adaptee {
  specialRequest() {
    console.log("special request");
  }
}
class Adapter implements Target {
  request() {
    new Adaptee().specialRequest();
  }
}
new Client().doSomeThing(new Adapter());

2. bridge(桥接)

  1. 描述:

Decouple an abstraction from its implementation so that the two can vary independently.

  1. 解释:将接口和实现分离以便独立变化
    结构如下:
  2. 实现
    常规的接口和实现的是固定的,对应的实现也很难扩展,通过将接口中对实现的约束指向另一个接口,从而将接口和实现分离
    Abstraction 抽象类接口,维护一个指向特定接口的引用。其中也可以包含通用的方法
    Implementor 定义实现类的接口
    ConcreteImplementor 对Implementor接口具体实现
    RefineAbsstraction 对Abstraction的实现
interface Implementor {
  operationImplementation(): string;
}
class ConcretorImplementor implements Implementor {
  operationImplementation() {
    return "Concretor";
  }
}
class Abstraction {
  protected implementation: Implementor;

  constructor(implementation: Implementor) {
    this.implementation = implementation;
  }
  public operation(): string {
    const result = this.implementation.operationImplementation();
    return "default" + result;
  }
}
class RefineAbsstraction extends Abstraction {
  operation() {
    const result = this.implementation.operationImplementation();
    return "refined" + result;
  }
}
console.log(new RefineAbsstraction(new ConcretorImplementor()).operation());

3. composite(组合)

  1. 描述:

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

  1. 解释:将对象组合成“部分-整体”的层次关系,并含有通用接口对外提供。 结构图:
  2. 实现: 结构类似一棵树,调用一个节点的方法,会递归调用所有子结点的对应方法 Component 根节点,声明了所有节点共有的接口和管理子结点的接口,并可以包含默认实现 Composite 根节点的实现 Leaf 叶子节点,只实现了所有节点共有的接口
class Component {
  protected Children: Component[] = [];
  constructor(public id) {}
  add(v: Component) {
    this.Children.push(v);
    return this;
  }
  remove(v: Component) {
    this.Children.splice(
      this.Children.findIndex((item: Component) => item.id === v.id),
      1
    );
  }
  getChildren() {
    return this.Children;
  }
  operation() {
    console.log("我是根节点" + this.id);
    this.Children.forEach((item: Component) => item.operation());
  }
}
class Composite extends Component {
  operation() {
    console.log("我一般节点" + this.id);
    this.Children.forEach((item: Component) => item.operation());
  }
}
class Leaf extends Component {
  operation() {
    console.log("我叶节点" + this.id);
  }
}
const root = new Component(1)
  .add(new Composite(2).add(new Leaf(4)))
  .add(new Leaf(3));
root.operation();

4. decorator(装饰器)

  1. 描述:

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

  1. 解释:动态的为对象添加另外的功能,不通过子类来实现。 结构图如下:
  2. 实现:
    Component 定义一个对象接口,可以给这些对象添加功能
    ConcreteComponent Component的实现
    Decorator 有一个指向修改对象的指针和相同的实现
    ConcreteDecoretor 具体进行添加功能操作的class
interface Component {
  operation(): string;
}

class ConcreteComponent implements Component {
  operation() {
    return "ConcreteComponent";
  }
}
class Decorator implements Component {
  constructor(protected component: Component) {}
  operation() {
    return this.component.operation();
  }
}
class ConcreteDecoretor extends Decorator {
  operation() {
    return "concrete-" + super.operation();
  }
}
console.log(new ConcreteDecoretor(new ConcreteComponent()).operation());

5. facade(外观)

  1. 描述:

Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

  1. 解释:为子系统中的一系列接口提供一个统一的接口
    结构如下:
  2. 实现: Facade 对外暴露的接口
    SubSystem 各个子系统
class Facade {
  constructor(private member1: SubSystem1, private member2: SubSystem2) {}
  operation() {
    this.member1.operator1();
    this.member2.operator2();
  }
}
class SubSystem1 {
  operator1() {
    console.log("子系统1工作");
  }
}
class SubSystem2 {
  operator2() {
    console.log("子系统2工作");
  }
}

new Facade(new SubSystem1(), new SubSystem2()).operation();

6. flyweight(享元)

  1. 描述:

Use sharing to support large numbers of fine-grained objects efficiently.

  1. 解释:利用缓存实现对对象的共享,以满足对大量对象的需要(享元这个词翻译的水平真的不好说
    结构图如下:

    共享对象组成的集合,flyweight pool
  2. 实现:
    Flyweight:创建共享对象的class,这里直接实例化进行共享,而不像结构图中用其子类了
    FlyweightFactory:生成共享池
class Flyweight {
  constructor(private shareState) {}
  operation(uniqueState) {
    console.log(`共享数据:${this.shareState};非共享数据:${uniqueState}`);
  }
}
class FlyweightFactory {
  private flyweights: { [key: string]: Flyweight } = <any>{}; //共享池
  add(shareState) {
    this.flyweights[JSON.stringify(shareState)] = new Flyweight(shareState); //注意这里由于JSON.stringify造成的对参数的限制
    return this;
  }
  //参数getExistOnly为true只获得当前pool中已经存在的,否则返回为undefined,用于验证缓存是否被启用
  getFlyweight(shareState, getExistOnly: boolean = false) {
    const targetFlyWeight = this.flyweights[JSON.stringify(shareState)];
    if (targetFlyWeight || getExistOnly) {
      return targetFlyWeight;
    }
    const newFlyWeight = new Flyweight(shareState);
    this.flyweights[JSON.stringify(shareState)] = newFlyWeight;
    return newFlyWeight;
  }
}
const flyWeightPool = new FlyweightFactory();
flyWeightPool.add({ a: 1 }).add({ b: 2 });
//注意以下验证严格等于时需要将带daigetExistOnly参数的放在左边,
//根据 https://tc39.es/ecma262/#sec-equality-operators-runtime-semantics-evaluation
//进行比较时会先计算左边,否则即使原本池子里不存在,也会新创建一个,导致左右始终相等,如第三个log
console.log(
  flyWeightPool.getFlyweight({ a: 1 }, true) ===
    flyWeightPool.getFlyweight({ a: 1 })
); //true
console.log(
  flyWeightPool.getFlyweight({ a: 3 }, true) ===
    flyWeightPool.getFlyweight({ a: 3 })
); //false
console.log(
  flyWeightPool.getFlyweight({ a: 4 }) ===
    flyWeightPool.getFlyweight({ a: 4 }, true)
); //true

7. proxy(代理)

  1. 描述:Provide a surrogate or placeholder for another object to control access to it.
  2. 解释:对对象的访问进行控制 结构如下:
    运行时刻的代理结构
  3. 实现:
    Proxy 实现代理功能的class
    RealObject 实际访问的对象
    Subject 定义代理和实际对象的共有接口
interface Subject {
  request(): string;
}
class RealObject implements Subject {
  request() {
    return "real";
  }
}
//因为在ts中已经存在Proxy关键字,这里以ProxySubject 替代
class ProxySubject implements Subject {
  constructor(private realObject) {}
  request() {
    return "proxy-" + this.realObject.request();
  }
}
console.log(new ProxySubject(new RealObject()).request());

Behavioral Patterns(行为模式)

包含算法和对象间的职责分配。

1. chain of responsibility(职责链)

  1. 描述:

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

  1. 解释:将处理对象连成一条链,前面的对象接收到请求,如果能处理则处理否则传给下一个,直到被处理(或者到最后也没处理),从而将请求方和处理方解耦。 结构如下:
    典型的对象结构如下
  2. 实现:
    Handler 处理对象的接口
    ConcreteHandler 具体的处理对象
class Handler {
  private nextHandler: Handler;
  setNext(h: Handler) {
    this.nextHandler = h;
    return h;
  }
  //默认处理,如果有下一个则交给下一个处理,否则返回'remnant',可以通过是不是null来判断是不是最后也没处理
  handle(request: number) {
    if (this.nextHandler) {
      return this.nextHandler.handle(request);
    }
    return "remnant";
  }
}

class ConcreteHandler1 extends Handler {
  handle(request: number) {
    if (request === 1) {
      return "done by handle1";
    }
    return super.handle(request);
  }
}
class ConcreteHandler2 extends Handler {
  handle(request: number) {
    if (request === 2) {
      return "done by handle2";
    }
    return super.handle(request);
  }
}
const handler1 = new ConcreteHandler1();
const handler2 = new ConcreteHandler2();
handler1.setNext(handler2);
console.log(handler1.handle(1));
console.log(handler1.handle(2));
console.log(handler1.handle(3));

2. command(命令)

  1. 描述:

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

  1. 解释:将请求封装成对象,然后以回调的形式调用各种操作。(取消操作暂不考虑)
    结构如下:
  2. 实现:
    Command 命令接口
    ConcreteCommand 具体的命令,会绑定在对应Receiver上
    Receiver 命令的接收者
    Invoker 挂载各种命令的对象接口
class Command {
  constructor(protected receiver: Receiver) {
    console.log(receiver);
  }
  execute() {
    console.log("default execute");
  }
}
class Receiver {
  constructor(private name = "") {}
  action() {
    console.log("name:" + this.name);
  }
}
class ConcreteCommand extends Command {
  execute() {
    console.log("concrete execute");
    this.receiver.action();
  }
}
class Invoker {
  private defaultStep = () => {
    console.log("default step");
  };
  onStep1: () => void = this.defaultStep;
  onStep2: () => void = this.defaultStep;
  setStep1(c: Command) {
    this.onStep1 = c.execute.bind(c);//注意这里绑定this,不然执行其中的this指向invoker
  }
  setStep2(c: Command) {
    this.onStep2 = c.execute.bind(c);
  }
}
const invoker = new Invoker();
invoker.setStep1(new ConcreteCommand(new Receiver("xiaoming")));
invoker.onStep1();
invoker.onStep2();

3. interpreter(解释器)

  1. 描述:

Given a language, define a represention for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

  1. 解释:就是一个指定规则的解释器,也可以简化为基于一种关系的映射。
    结构:
  2. 实现:这里将解释器的作用简化为一种映射,这个模式的重点在于具体解释规则的指定
class Expression {
  interpret(props: string) {
    return props.length;
  }
}
console.log(new Expression().interpret("2222"));

4. iterator(迭代器)

  1. 描述:Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
  2. 解释:提供一个顺序访问对象元素的方法,而不暴露底层实现,其实ts在语言层面已经实现得很好了
    结构:
  3. 实现:以下实现的是对数组的迭代
    Iterator 迭代器对象接口
    ConcretorIterator 具体迭代对象
    Aggregator 要迭代的对象接口
    ConcreteAggregator 具体要迭代的对象
interface IteratorInterface<T> {
  first(): T;
  next(): T;
  isDone: boolean;
  curItem: T;
}
interface Aggregator {
  createIterator(): IteratorInterface<string>;
}
class ConcreteAggregator implements Aggregator {
  items: string[] = [];
  addItem(i: string) {
    this.items.push(i);
    return this;
  }
  createIterator() {
    return new ConcreteIterator(this);
  }
}
class ConcreteIterator implements IteratorInterface<string> {
  location: number = 0;
  constructor(private collection: ConcreteAggregator) {}
  first() {
    return this.collection.items[0];
  }
  next() {
    const item = this.collection.items[this.location];
    this.location += 1;
    return item;
  }
  get isDone() {
    return this.location >= this.collection.items.length;
  }
  get curItem() {
    return this.collection.items[this.location];
  }
}
const aggregator = new ConcreteAggregator();
aggregator.addItem("first").addItem("second").addItem("third");
const iterator = aggregator.createIterator();
while (!iterator.isDone) {
  console.log(iterator.next());
}

5. mediator(中介)

  1. 描述:

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

  1. 解释:用一个对象封装一系列的对象交互,各对象交互低耦合
    结构图:
  2. 实现: Mediator 中介接口,定义了一个通信的方法
    ConcreteMediator 具体中介 Colleague 一系列需要协同的对象
interface Mediator {
  notify(receiver: string): void;
}
class ConcreteMediator implements Mediator {
  constructor(private c1: Colleague, private c2: Colleague) {
    c1.setMediator(this);
    c2.setMediator(this);
  }
  notify(receiver) {
    this[receiver] && this[receiver].toDo();
  }
}
class Colleague {
  mediator: Mediator;
  setMediator(m: Mediator) {
    this.mediator = m;
  }
  toDo() {}
  toCall(listener: string) {}
}
class ConcreteColleague1 extends Colleague {
  toDo() {
    console.log("对象1被被调用");
  }
  toCall(listener: string) {
    console.log("对象1发起调用");
    this.mediator.notify(listener);
  }
}
class ConcreteColleague2 extends Colleague {
  toDo() {
    console.log("对象2被被调用");
  }
  toCall(listener: string) {
    console.log("对象2发起调用");
    this.mediator.notify(listener);
  }
}
const c1 = new ConcreteColleague1();
const c2 = new ConcreteColleague2();
const m = new ConcreteMediator(c1, c2);
c1.toCall("c2");
c2.toCall("c1");

6. memento(备忘录)

  1. 描述:

Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.

  1. 解释:在不破坏封装性的前提下,在外部保存内部状态
    结构如下:
  2. 实现: Memento 备忘录
    Originator 需要备份的对象class
class Memento {
  private state: number;
  getState() {
    return this.state;
  }
  setState(state) {
    this.state = state;
  }
}
class Originator {
  constructor(private memento: Memento, public state: number) {}
  save() {
    this.memento.setState(this.state);
  }
  chenge() {
    this.state += 1;
  }
  check() {
    return this.memento.getState();
  }
}
const o = new Originator(new Memento(), 0);
console.log(o.state);
o.save();
o.chenge();
console.log(o.state);
console.log(o.check());

7. observer(观察者)

  1. 描述:

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

  1. 解释:定义一个一对多的依赖关系,一个对象变化时,所有依赖该对象的对象都会被通知
    结构: 3.实现:
    Observer 观察者接口
    Subject 观察者的依赖接口
interface Observer {
  update(state: number): void;
  observerState: number;
}
class ConcreteObserver implements Observer {
  observerState = 0;
  constructor(public id) {}
  update(state) {
    this.observerState = state;
  }
}
class Subject {
  constructor(private state: number) {}
  observers: ConcreteObserver[] = [];
  init() {
    this.notify();
  }
  attach(o: ConcreteObserver) {
    if (!this.observers.find((item) => item.id === o.id)) {
      this.observers.push(o);
    }
    return this;
  }
  detach(o: ConcreteObserver) {
    const index = this.observers.findIndex((item) => (item.id = o.id));
    this.observers.splice(index, 1);
  }
  notify() {
    console.log(this.observers);
    this.observers.forEach((item) => item.update(this.state));
  }
  modifyState() {
    this.state += 1;
    this.notify();
  }
}
const o1 = new ConcreteObserver("a");
const o2 = new ConcreteObserver("b");
const s = new Subject(1);
s.attach(o1).attach(o2).init();
console.log(o1.observerState);
console.log(o2.observerState);
s.modifyState();
console.log(o1.observerState);
console.log(o2.observerState);

8. state(状态)

  1. 描述:

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

  1. 解释:对象的行为根据状态改变而改变
    结构图:
  2. 实现:
    State 状态接口
    ConstrateState 具体状态
    Context 维持状态的环境
interface State {
  handler(): void;
}
class ConstrateState1 implements State {
  handler() {
    console.log("state1");
  }
}
class ConstrateState2 implements State {
  handler() {
    console.log("state2");
  }
}

class Context {
  constructor(private state: State) {}
  transitionTo(state: State) {
    this.state = state;
  }
  request() {
    this.state.handler();
  }
}
const s1 = new ConstrateState1();
const s2 = new ConstrateState2();
const context = new Context(s1);
context.request();
context.transitionTo(s2);
context.request();

9. strategy(策略)

  1. 描述:

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

  1. 解释:封装一系列可以互相替换的策略
    结构如下:
  2. 实现:
    状态模式和策略模式的结构图几乎一样,具体实现可以参考状态模式。它们俩的不同至少有两个方面
    1)目的不同,状态模式根据状态的切换不同做法,策略模式是存在几种可以替换的策略
    2)不同状态是互相依赖的,不同策略没有这种关系。

10. template Method(模板方法)

  1. 描述:

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

  1. 解释:定义一个算法在操作中的框架,可以在不改变框架的前提下修改特定步骤,可用于创建hook,比如vue或react中特定生命周期钩子函数。
    结构:
  2. 实现: AbstractClass 抽象类中包含默认步骤和模板方法
    ConstreteClass 具体类可以修改某些步骤,如果重定义则执行新的,否则执行默认的
abstract class AbstractClass {
  operation1() {
    console.log("default operation1");
  }
  operation2() {
    console.log("default operation1");
  }
  templateMethod() {
    this.operation1();
    this.operation2();
  }
}
class ConstreteClass extends AbstractClass {
  operation1() {
    console.log("constrete operation");
  }
}
new ConstreteClass().templateMethod();

11. visitor(访问者)

  1. 描述:

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

  1. 解释:在不改变被访问对象的前提下,修改该对象内部的操作行为,比如babel中的visitor 。 结构图:
  2. 实现: Element 被访问对象接口 ConcreteElement 具体访问的元素
    Visitor 访问者接口,包含访问行为
    ConcreteVisitor 具体的访问者,包含具体的访问行为
interface Visitor {
  visitA(e: ConcreteElementA): void;
  visitB(e: ConcreteElementB): void;
}
class ConstreteVisitor1 implements Visitor {
  visitA(e) {
    console.log(e);
    console.log(`第一种对A的访问,id为:${e.state}`);
  }
  visitB(e) {
    console.log(`第一种对B的访问,id为:${e.state}`);
  }
}
interface ElementInterface {
  accept(visitor: Visitor): void;
}
class ConcreteElementA implements ElementInterface {
  state = "a";
  accept(visitor: Visitor) {
    visitor.visitA(this);
  }
}
class ConcreteElementB implements ElementInterface {
  state = "b";
  accept(visitor: Visitor) {
    visitor.visitB(this);
  }
}
new ConcreteElementA().accept(new ConstreteVisitor1());
new ConcreteElementB().accept(new ConstreteVisitor1());

设计原则

设计原则(design principles)指的是抽象性比较高、编程都应该遵守的原则,对应的设计模式(design patten)是解决具体场景下特定问题的套路,这里要对两个概念进行区分。换句话说,设计模式要遵循设计原则。

设计原则这里以SOLID为例加以介绍,其他原则这里暂不讨论。
solid是五个原则单词的首字母缩写,分别为

Single-responsibility principle

单一职责原则,每个class只负责一件事,即一个class只能有一个改变的理由。

Open–closed principle

开放封闭原则,软件实体(包括classes, modules, functions)应开放从而被扩展,但是应关闭阻止被修改。

Liskov substitution principle

里氏替换原则,在一个程序中,如果S是T的子类型,T类型的对象可以直接被S类型对象替换而不需更改。

Interface segregation principle

接口隔离原则,lient-specific 接口比通用接口好一些,因为通用接口有很多用不到的方法

Dependency inversion principle

依赖倒置原则,上层模块和下层模块减少耦合,二者具体的实现应都依赖对应抽象。


完结撒花