1. Singleton Pattern

1.1 define

Ensure that there is only one instance of a class and provide a global access method for the current class. It addresses the frequent creation and destruction of a globally used class. Note that a singleton class has only one instance; A singleton class must create its own unique instance; The singleton class must provide this instance to all other objects.

1.2 Implementation of singleton pattern

Check if the instance exists, and return if it does, and create and return if it does not. This ensures that a class has only one instance object.

// ES6 class
class Singleton {
  private static instance: Singleton
  private constructor() {}

  static getInstance(): Singleton {
    if(! Singleton.instance)return Singleton.instance = new SingleTon()
    return SingleTon.getInstance()
  }
}
const instance = Singleton.getInstance()
console.log(instance)
Copy the code

The js closure implements singletons

const CustomClass = function() {}

const Singleton = (function() {
  let instance = null

  return function () {
    if(! instance) instance =new CustomClass()
    return instance
  }
})()
const singleton = new Singleton()
console.log(singleton)
Copy the code
 // Antd Notification singleton pattern prevents instances from being generated repeatedly
function getNotificationInstance({
    prefixCls,
    placement,
    getContainer,
  }, callback: (n: any) = >void) {
  const cacheKey = `${prefixCls}-${placement}`;
  if (notificationInstance[cacheKey]) {
    callback(notificationInstance[cacheKey]);
    return;
  }
  // Instantiate the Notification component
  (Notification as any).newInstance(
    {
     / /... The configuration information........ is omitted
    },
    (notification: any) = > {
      // Cache the instancenotificationInstance[cacheKey] = notification; callback(notification); }); }Copy the code
1.3 Application Scenarios

A single object, such as a modal box, is created only once, no matter how many times it is clicked. The ANTD component library provides components such as Notification and Message that use this design pattern. Advantage: Only one object in memory, saving memory space; Avoid frequent creation and destruction of objects to improve performance; Disadvantage: Cannot be used for frequently changing objects

2. Strategy Pattern

2.1 define

The policy pattern defines a series of algorithms, encapsulates each algorithm and makes them interchangeable, allowing the algorithm to change independently of the user who uses it. The goal is to separate the use and implementation of the algorithm.

When can you use the policy pattern

  • If a class defines multiple behaviors in the form of multiple conditional statements in the class’s methods, you can use the policy pattern to avoid using a large number of conditional statements (if… The else…). .
  • Programs that do not want to expose complex algorithm-related data structures can use policy patterns to encapsulate algorithms.
  • You need to use different variations of an algorithm.
2.2 Implementation of policy mode
2.2.1 steps
  • Context Sets the policy and the Context class that executes it; The context in which the policy is manipulated
  • Stragety strategy abstraction; Policy class features can be extracted as interfaces and implemented with the implements keyword. Other classes can inherit interfaces.
  • ConcreteStragetyA, ConcreteStragetyB concrete strategy implementation.
2.2.2 implementation

//
const calSalary = function( level, salary ) {
  if ( level === 'A') return salary * 3;
  if ( performanceLevel === 'B') return salary * 2
  if ( performanceLevel === 'C') return salary
};

calSalary( 'B'.10000 ); / / 10000
calSalary( 'A'.10000 ); / / 20000
Copy the code
interface Strategy {
  calSalary(value: string) :void;
}

class Context {
  private strategy: Strategy;
  private salary: number;

  constructor(value: number) {
    this.salary = value;
  }

  public setStrategy(strategy: Strategy) {
    this.strategy =  strategy;
  }

  public execute() {
    this.strategy.calSalary(this.salary); }}class ConcreteStragetyA implements Strategy {
  public calSalary(value: number) :void {
    return value * 3}}class ConcreteStragetyB implements Strategy {
  public calSalary(value: number) :void {
    return value * 2}}class ConcreteStragetyC implements Strategy {
  public calSalary(value: number) :void {
    return value
  }
}

const context: Context = new Context(10000);
// getSalary higher salary 30000
context.setStrategy(new ConcreteStragetyA());
context.execute();
// getSalary middle salary 20000
context.setStrategy(new ConcreteStragetyB());
context.execute();
// getSalary lower salary 10000
context.setStrategy(new ConcreteStragetyC())
context.exeute()
Copy the code
2.3 Application Scenarios

Form validation; Calculate taxes in different countries; Advantages: Avoid multiple conditional judgments for multiple behaviors of the same class; The strategy algorithm can switch freely. Disadvantages: A wide variety of policies; All policy classes need to be exposed

3. Observer Pattern

3.1 define

Define a one-to-many dependency between objects so that whenever an object’s state changes, its dependent objects are notified and automatically updated. The observer pattern is similar to the publish-subscriber pattern in that the publish-subscribe pattern is one of the most commonly used implementations of the observer pattern and is superior to the typical observer pattern in terms of decoupling and reuse.

Publish subscription VS Observer

  • Publish the subscriber model
    • When subscribing to an event, subscribers only care about the event itself, and do not care about who publishes the event. Publishers only care about the event when they publish it, not who subscribes to it.
    • The subscription publishing pattern maintains relationships between topics (events) and objects that depend on each topic (events), and the publication subscribers are{ event1->[obj1,obj2....] , event2->[obj1,obj2.....] . }
    • Eg: Customer – Taobao – merchant relationship in Taobao shopping; Customers belong to Subscriber, Taobao is equivalent to Event Channel, and merchants are equivalent to Publisher.
  • Observer model
    • When the observer and the observer target are coupled together, it is necessary to introduce both the observer and the observer target to achieve responsiveness, which is not flexible.
    • Observer isevent->[obj1,obj2obj3,....]
    • Eg: Wechat business and customers belong to the observer model; Wechat business belongs to the observer target (Subject) and customers belong to Obeserve (Obeserve)
3.2 Code Implementation

Observer model

interface Observer {  
  notify() = > void;
}
interface Subject {
  addObserver(observer: Observer) = > void;
  deleteObserver: (observer: Observer) = > void;
  notifyObservers: () = > void;
}

class ConcreteSubject implements Subject{   
  private observers: Observer[] = []; 
  // Add an observer
  public addObserver(observer: Observer): void {   
     this.observers.push(observer); 
  } 
  // Remove the observer
  public deleteObserver(observer: Observer): void {    
      const idx: number = this.observers.indexOf(observer); (idx ! = = -1) && this.observers.splice(idx, 1); 
  }
  // Notify the observer list
  public notifyObservers(): void {   
    console.log("notify all the observers ".this.observers); 
    this.observers.forEach(observer= >{ observer.notify(); }); }}class ConcreteObserver implements Observer{  
  constructor(private name: string) {} 
  notify(): void {   
    console.log(`The ${this.name} has been notified.`); }}function useObserver() :void {  
  const subject: Subject = new ConcreteSubject();  
  const obeserve1 = new ConcreteObserver("mumiao");  
  const obeserve2 = new ConcreteObserver("zhenglin");  
  subject.addObserver(obeserve1);
  subject.addObserver(obeserve2);  
  subject.notifyObservers();   
  subject.deleteObserver("mumiao");  
  subject.notifyObservers();
}
useObserver();
Copy the code

Publisher-subscriber model

interface Publisher {
  subscriber: string;
  data: any;
}

interface EventChannel {
  on  : (subscriber: string, callback: () => void) = > void;
  off : (subscriber: string, callback: () => void) = > void;
  emit: (subscriber: string, data: any) = > void;
}

interface Subscriber {
  subscriber: string;
  callback: () = > void;
}

class ConcreteEventChannel implements EventChannel {
  // Initialize the subscriber object
  private subjects: { [key: string] :Function[]} = {};// Implement adding subscription events
  public on(subscriber: string.callback: () = > void) :void {
    console.log('Received subscription message, subscription event:${subscriber}`);
    if (!this.subjects[subscriber]) {
      this.subjects[subscriber] = [];
    }
    this.subjects[subscriber].push(callback);
  };

  // Implement the unsubscribe event
  public off(subscriber: string.callback: () = > void) :void {
    console.log('Received unsubscribe request, need to cancel the subscription events:${subscriber}`);
    if (callback === null) {
      this.subjects[subscriber] = [];
    } else {
      const index: number = this.subjects[subscriber].indexOf(callback); index ! = = -1 && this.subjects[subscriber].splice(index, 1); }};// Implement publish subscribe events
  public emit (subscriber: string, data = null) :void {
    console.log('Receiving the publisher's message, execute the subscription event:${subscriber}`);
    this.subjects[subscriber].forEach(item= > item(data));
  };
}

class ConcretePublisher implements Publisher {
  public subscriber: string = "";
  public data: any;
  constructor(subscriber: string, data: any) {
    this.subscriber = subscriber;
    this.data = data; }}class ConcreteSubscriber implements Subscriber {
  public subscriber: string = "";
  constructor(subscriber: string, callback: () => void) {
    this.subscriber = subscriber;
    this.callback = callback;
  }
  public callback(): void{}; }/* Run the example */
const mumiao = new ConcreteSubscriber(
  "running".() = > {
    console.log("Subscriber mumiao subscribed to the event successfully! Execute callback ~"); });const zhenglin = new ConcreteSubscriber(
  "swimming".() = > {
    console.log("Subscriber zhenglin subscription event success! Execute callback ~"); });const pual = new ConcretePublisher(
  "swimming",
  {message: "Pual releases news ~"});const eventBus = new ConcreteEventChannel();
// Register the subscription event
eventBus.on(mumiao.subscriber, pingan8787.callback);
eventBus.on(zhenglin.subscriber, leo.callback);
// Send events
eventBus.emit(pual.subscriber, pual.data);
eventBus.off (mumiao.subscriber, lisa.callback);
Copy the code
3.3 Application Scenarios

Vue response; Event binding;

4. Decorator Pattern

4.1 define

On the basis of not changing the original object, the original object can meet the more complex needs of users by packaging and expanding it

4.2 Code Implementation

Decorator mode

class Component {
    constructor() {
      console.log('Component Class created');
    }
    operation() {
      console.log('Component.operation invoked'); }}class ConcreteComponent extends Component {
    constructor() {
      super(a);console.log('ConcreteComponent Class created');
    }
    operation() {
        console.log('ConcreteComponent.operation invoked'); }}class Decorator extends Component {
    constructor(component) {
      super(a);this.component = component;
      console.log('Decorator Class created');
    }
    operation() {
      console.log('Decorator.operation invoked');
      this.component.operation()
    }
}

class ConcreteDecoratorA extends Decorator {
    constructor(component, sign) {
        super(component);
        this.addedState = sign;
        console.log('ConcreteDecoratorA Class created');
    }
    operation() {
        super.operation();
        console.log('ConcreteDecoratorA.operation invoked');
        console.log(this.addedState)
    }
}

var component = new ConcreteComponent();
var decoratorA = new ConcreteDecoratorA(component, 'decoratorA');
console.log('component: ');
component.operation();
console.log('decoratorA: ');
decoratorA.operation();

> "Component Class created"
> "ConcreteComponent Class created"
> "Component Class created"
> "Decorator Class created"
> "ConcreteDecoratorA Class created"
> "component: "
> "ConcreteComponent.operation invoked"
> "decoratorA: "
> "Decorator.operation invoked"
> "ConcreteComponent.operation invoked"
> "ConcreteDecoratorA.operation invoked"
> "decoratorA"
Copy the code

ES7 adds spring. Decorate the class with an @ syntax sugar

// The decorator function whose first argument is the target class
function classDecorator(target) {
    target.hasDecorator = true
    return target
}
// "install" the decorator on the Button class
@classDecorator
class Button {
    // The related logic of the Button class
}
console.log('Button is decorated: ', Button.hasDecorator) // true
Copy the code

Decorates a method of the class

function funcDecorator(target, name, descriptor) {
    // Target indicates that the class's prototype name is the function name descriptor
    let originalMethod = descriptor.value
    descriptor.value = function() {
    console.log('I am the decorator logic of Func')
    return originalMethod.apply(this.arguments)}return descriptor
}

class Button {
    @funcDecorator
    onClick() {
        console.log('I am the original logic of Func')}}Copy the code

See ES7 for details on other @ decorators

4.3 Application Scenarios

React high-order components; The react – redux connect components

[

] (dtstack.yuque.com/rd-center/s…).