Both design patterns and design principles are for object-oriented programming, and other programming paradigms do not fit well. See this article for programming paradigms. The implementation uses typescript. If you are not familiar with TS, please refer to this article.


Design patterns

Refer here to Design Patterns: Elements of Reusable Object-oriented Software.

What are design patterns

The definition of design patterns is derived from the concept of an architectural pattern:

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

Similar to architectural patterns, object-oriented design patterns are a set of major solutions to recurring problems in our daily development.

classification

Design patterns fall into three categories, and they are

  • Creational
  • The structure of the building is very Structural.
  • Behavioral behavior

Describe each design pattern

We’ll use this format when we talk about each design pattern, so we can get a clearer picture of each pattern.

  1. Description: Refer directly to the Intent section of the book to understand the design pattern from the original description;
  2. 2. Contains an interpretation of the description, and a structure diagram;
  3. Implementation: appropriate annotation to the implementation, and give the specific code implementation (the structure diagram is the original picture in the book, the specific implementation will have some differences).

Creational Patterns

It is used for object creation and encapsulates the created logic, exposing only the necessary apis to the outside world to increase the flexibility of the concrete implementation.

1. Factory method

  1. Description:

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. Definition: A class Creator contains an abstract factory method whose subclasses decide which class to instantiate.

Structure is as follows

  1. Implementation:

Product defines the object interface created by the factory method ConcreteProduct. Creator declares the factory method ConcreteCreator, which implements the factory method. To instantiate the ConcreteProduct 1) implement the above structure first

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

2) The obvious problem with the factory method is that every time you instantiate a new Product subclass, you have to create a subclass of Creator. Here’s an improvement: Creator itself can provide a default factorMethod method, and you can also extend it by creating a subclass. 3) Another variation of the factory method is the parameter factory method, where the Creator class directly instantiates different classes based on the parameters and returns them

class Creator { factorMethod(type: "A" | "b") {if (type = = = "a") and returns} {/ / instantiate a subclass if (type = = = "b") {/ / instantiate another subclass and return} throw "no correct type"; } } //new Creator().factorMethod('a').someOperation()Copy the code

2. Prototype

  1. Description:

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

  1. Explanation: Specify an instance object as a prototype, and then create a new object by copying that object.

There are different implementation methods for this pattern in different languages. The implementation method in the book is based on the premise that c++ class is not an object. In ts, the inheritance mechanism based on prototype is born with prototype, so it can be directly used.

  1. With the object.create () method, you can specify a prototype directly and override or add attributes to the prototype with parameters. Note that if attributes on the stereotype are not overridden, changes in attributes on the stereotype will affect attributes on the inherited object.
Var vehiclePrototype = {name: "aaaaa", getName: function () {console.log("name is: "+ this.name); }}; var vehicle = Object.create(vehiclePrototype, { name: { value: "bbbbb", }, }); console.log(vehicle.getName()); console.log(vehiclePrototype.getName());Copy the code

3. Abstract Factory

  1. Description:

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

  1. Explanation: Provides an interface for creating similar or interdependent objects, that is, producing a series of factories for producing multiple families of objects.

The structure is as follows:3. Implementation:

AbstractFactory is an abstract class that contains two abstract methods.

The ConcreteCreator in the Factory method pattern contains the factory method

AbtractProduct is the Product in the factory method pattern, implemented as follows

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; Class ConcreteFactory1 implements AbstractFactory {public createProductA(): ConcreteFactory1 implements AbstractFactory (); AbstractProductA { return new ConcreteProductA1(); } public createProductB(): AbstractProductB { return new ConcreteProductB1(); Class ConcreteFactory2 implements AbstractFactory {public createProductA(): implements AbstractFactory (); AbstractProductA { return new ConcreteProductA2(); } public createProductB(): AbstractProductB { return new ConcreteProductB2(); Console.log (new ConcreteFactory1().createProducta ().usefulfunctiona ()));Copy the code

4. The builder

  1. Description:

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

  1. Explanation: Separate the initialization of an object from subsequent steps. By combining initialization with different subsequent steps, different results can be created.

Structure is as follows



3. Implementation:

The Director constructs an object that uses the Buidler interface

Builder specifies the abstract interface for creating the various parts of the Product object

ConcreteBuilder implements the interface to The Builder and provides a way to get the result of the implementation 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());
Copy the code

5. singleton

  1. Description:

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

  1. Explanation: Ensure that only one instance of a class is available for global access.

The structure is as follows:



3. Implementation:

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);Copy the code

Structural Patterns

Used to combine classes and objects

1. Adapter

  1. Description:

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. Explanation: Make two incompatible interfaces work together

The structure is as follows:3. Implementation:

The Client invokes the Request method

Target defines the interface that the client calls

Adaptee An existing interface. An Adapter is required to adapt the Adaptee and the interface 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());
Copy the code

2. Bridge

  1. Description:

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

  1. Explanation: Separate the interface and implementation for independent variation

The structure is as follows:

3. The implementation

The conventional interface and implementation are fixed, and the corresponding implementation is difficult to extend. The interface and implementation are separated by pointing the constraints on the implementation in the interface to another interface

Abstraction class interface, maintains a reference to a specific interface. It can also contain generic methods

Implementor Defines the interface that implements the class

ConcreteImplementor Implements the Implementor interface

RefineAbsstraction implementation of 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());
Copy the code

3.

  1. Description:

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

  1. Explanation: To group objects into a “partial-whole” hierarchy, with a common interface provided externally.

Structure:3. Implementation: A method that calls a node recursively calls the corresponding methods of all its children, the Component root node, declares interfaces common to all nodes and interfaces that manage its children, and can include an implementation Leaf node that implements the Composite root node by default. Only interfaces common to all nodes are implemented

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(" I am the root node "+ this.id); this.Children.forEach((item: Component) => item.operation()); }} class Composite extends Component {operation() {console.log(" console.log "+ this.id); this.Children.forEach((item: Component) => item.operation()); }} class Leaf extends Component {operation() {console.log(" my Leaf "+ this.id); } } const root = new Component(1) .add(new Composite(2).add(new Leaf(4))) .add(new Leaf(3)); root.operation();Copy the code

4. Decorator

  1. Description:

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

  1. Add additional functionality to an object dynamically, without subclassing it.

The structure diagram is as follows:3. Implementation:

Component defines an interface to objects to add functionality to

Implementation of the ConcreteComponent Component

The Decorator has a pointer to the modified object and the same implementation

ConcreteDecoretor Class for concrete add function operations

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());
Copy the code

5. Facade

  1. Description:

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. Explanation: To provide a unified interface for a series of interfaces in a subsystem

The structure is as follows:3. Implementation: Facade Indicates the exposed interface

SubSystem

class Facade { constructor(private member1: SubSystem1, private member2: SubSystem2) {} operation() { this.member1.operator1(); this.member2.operator2(); }} class SubSystem1 {operator1() {console.log(" SubSystem1 works "); }} class SubSystem2 {operator2() {console.log(" SubSystem2 works "); } } new Facade(new SubSystem1(), new SubSystem2()).operation();Copy the code

6. Flyweight

  1. Description:

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

  1. The use of cache to achieve the object sharing, to meet the needs of a large number of objects.

The structure diagram is as follows:



A collection of shared objects, the Flyweight pool3. Implementation:

Flyweight: Creates the class of the shared object, which is instantiated directly instead of subclassing it like the structure diagram

FlyweightFactory: Generates a shared pool

Class Flyweight {constructor(private shareState) {} operation(uniqueState) {console.log(' Share data: ${this.shareState}; ${uniqueState} '); } } class FlyweightFactory { private flyweights: { [key: string]: Flyweight } = <any>{}; // Add (shareState) {this.flyweights[json.stringify (shareState)] = new Flyweight(shareState); Return this; return this; GetFlyweight (shareState, getExistOnly:) {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 }); // Note that the following validation is strictly equal to place the parameter with daigetExistOnly on the left, // According to https://tc39.es/ecma262/#sec-equality-operators-runtime-semantics-evaluation // the left side will be calculated first, otherwise a new pool will be created even if the original pool does not exist, Leading to about equal all the time, such as the third log console. The 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) ); //trueCopy the code

7. Proxy

  1. Provide a surrogate or placeholder for another object to control access to it.
  2. Explanation: Controls access to objects

The structure is as follows:

Run-time proxy structure3. Implementation:

Proxy Class for implementing the Proxy function

RealObject Object that is actually accessed

Subject defines the common interface between the proxy and the real object

interface Subject { request(): string; } class RealObject implements Subject { request() { return "real"; }} // Since the Proxy keyword already exists in ts, Class ProxySubject implements Subject {constructor(private realObject) {} Request () {return "proxy-" + this.realObject.request(); } } console.log(new ProxySubject(new RealObject()).request());Copy the code

Behavioral Patterns

Includes assignment of responsibilities between algorithms and objects.

1. Chain of responsibility

  1. Description:

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. Explanation: Decouple the requestor from the handler by connecting the processing objects in a chain in which the preceding object receives the request, processes it if it can, or passes it on to the next until it is processed (or not processed at all).

The structure is as follows:

The typical object structure is as follows3. Implementation:

Handler Handles the interface of an object

ConcreteHandler Specifies the object to handle

class Handler { private nextHandler: Handler; setNext(h: Handler) { this.nextHandler = h; return h; } // Handle by default, if there is a next handle to the next handle, otherwise return 'Remnant', which can be used to determine if the 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));Copy the code

2.

  1. Description:

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

  1. Explanation: Encapsulate the request as an object, and then invoke various operations as callbacks. (Cancel operation temporarily not considered)

The structure is as follows:3. Implementation:

Command Command interface

ConcreteCommand Specifies the command that is bound to the corresponding Receiver

Receiver Receiver of the command

Invoker mounts the object interface for various commands

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); } setStep2(c: Command) {this.onstep2 = c.ecute.bind (c); } } const invoker = new Invoker(); invoker.setStep1(new ConcreteCommand(new Receiver("xiaoming"))); invoker.onStep1(); invoker.onStep2();Copy the code

3. Interpreter

  1. Description:

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

  1. Interpretation: Even an interpreter that specifies rules can be reduced to a mapping based on a relationship.

Structure:3. Implementation: The role of the interpreter is reduced to a mapping, which focuses on the specification of specific interpretation rules

class Expression {
  interpret(props: string) {
    return props.length;
  }
}
console.log(new Expression().interpret("2222"));
Copy the code

4. Iterator

  1. Description: Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
  2. Explanation: To provide a way to access object elements sequentially without exposing the underlying implementation, ts is already well implemented at the language level

Structure:

3. Implementation: The following implementation is an iteration of an array

Iterator Interface of an Iterator object

ConcretorIterator Concretes iterators

The object interface that the Aggregator iterates over

ConcreteAggregator Specifies the object to iterate over

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()); }Copy the code

5. Mediators

  1. Description:

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. Explanation: Encapsulate a set of object interactions with one object, with low coupling

Structure:

3. Implementation: Mediator interface, which defines a method of communication

ConcreteMediator A series of objects that need cooperation

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(" object 1 is called "); } toCall(listener: string) {console.log(" object 1 initiates the call "); this.mediator.notify(listener); }} class ConcreteColleague2 extends Colleague {toDo() {console.log(" Object 2 is called "); } toCall(listener: string) {console.log(" object 2 initiates the call "); this.mediator.notify(listener); } } const c1 = new ConcreteColleague1(); const c2 = new ConcreteColleague2(); const m = new ConcreteMediator(c1, c2); c1.toCall("c2"); c2.toCall("c1");Copy the code

6. Memento

  1. Description:

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

  1. Explanation: Save internal state externally without breaking encapsulation

The structure is as follows:

3. The end of the road

Originator Specifies the class of the object to be backed up

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());
Copy the code

An observer is an observer.

  1. Description:

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

  1. Definition: Defines a one-to-many dependency in which all dependent objects are notified when an object changes

Structure:3. Implementation:

Observer Observer interface

The dependent interface of the Subject observer

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);Copy the code

8.

  1. Description:

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

  1. Explanation: The behavior of an object changes based on state changes

Structure:3. Implementation:

State interface

ConstrateState Indicates the status

Context The Context that maintains the state

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();

Copy the code

9. Strategy

  1. Description:

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

  1. Explanation: Encapsulate a set of interchangeable policies

The structure is as follows:3. Implementation:

The structure diagram of the state pattern is almost the same as that of the policy pattern, and you can refer to the state pattern for implementation.The difference between the twoThere are at least two aspects

1) For different purposes, the state mode has different methods according to the state switch. In the policy mode, there are several strategies that can be replaced

2) Different states are interdependent, and different strategies have no such relationship.

10. Template Method

  1. Description:

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. Definition: Defines an algorithm in action framework, can modify the framework without changing the specific steps, can be used to create hooks, such as vue or React specific lifecycle hook functions.

Structure:AbstractClass abstract classes contain default steps and template methods

The ConstreteClass concrete class can modify certain steps, executing new ones if redefined, and default ones otherwise

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();

Copy the code

11. Visitor

  1. Description:

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. Explanation: Modify the behavior of operations inside an object without changing the object being accessed (in this case, visitor access)

Structure:3. Implementation: Element is accessorized to ConcreteElement

Visitor Interface that contains access behavior

ConcreteVisitor Concrete visitors that contain concrete visit actions

interface Visitor { visitA(e: ConcreteElementA): void; visitB(e: ConcreteElementB): void; } class ConstreteVisitor1 implements Visitor { visitA(e) { console.log(e); Console. log(' first access to A,id: ${e.state} '); } visitB(e) {console.log(' first access to 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());Copy the code

Design principles

Design Principles refer to principles that are abstract and should be followed by programming. Design patten refers to routines that solve specific problems in specific scenarios. Here, the two concepts should be distinguished. In other words, design patterns follow design principles.

The design principles are introduced here with SOLID as an example, and other principles are not discussed here. Solid is an acronym for five words of principle, respectively

Single-responsibility principle

The single responsibility principle, in which each class is responsible for one thing, means that a class can only have one reason to change.

The Open – closed principle

The open Closed principle is that software entities (including classes, modules, and functions) should be open to be extended, but closed to prevent modification.

Liskov substitution principle

Richter’s substitution principle, in a program, if S is a subtype of T, an object of type T can be replaced directly by an object of type S without change.

Interface segregation principle

As a principle of interface isolation, lient-specific interfaces are better than general-purpose interfaces, which have many methods that are not used

Dependency inversion principle

Dependency inversion principle, the upper module and the lower module reduce coupling, the concrete implementation of both should depend on corresponding abstraction.


End and spend