In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly explains "what are the common design patterns". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought. Let's study and learn "what are the common design patterns"?
1. Builder model
The Builder pattern (Builder Pattern) decomposes a complex object into relatively simple parts, then creates them according to different needs, and finally builds the complex object.
A car? It usually consists of four parts: engine, chassis, car body and electrical equipment. The internal structure of automotive electrical equipment is very complex, for simplicity, we only consider three parts: the engine, the chassis and the body.
In real life, cars are also made of different parts. For example, in the picture above, we divide the car into three parts: engine, chassis and body. Let's take a look at how to use the builder mode to build a car.
1.1 implementation code
Class Car {constructor (public engine: string, public chassis: string, public body: string) {} class CarBuilder {engineered: string; / / engine Chassisbodies: string; / / chassis bodyboards: string; / / body addChassis (chassis: string) {this.chassis = chassis; return this;} addEngine (engine: string) {this.engine = engine; return this } addBody (body: string) {this.body = body; return this;} build () {return new Car (this.engine, this.chassis, this.body);}}
In the above code, we define a CarBuilder class and provide three methods for assembling different parts of the car: addChassis, addEngine and addBody. When the three parts of the car are assembled, call the build method to start building the car.
1.2 examples of use
Const car = new CarBuilder () .addEngine ('v12') .addBody (' magnesium alloy') .addChloride ('composite') .build ()
1.3 Application scenarios and cases
The product objects that need to be generated have complex internal structures, and these product objects usually contain multiple member attributes.
The properties of the product objects that need to be generated depend on each other, and the order in which they are generated needs to be specified.
Isolate the creation and use of complex objects and enable the same creation process to create different products.
Github-node-sql-query: https://github.com/dresende/node-sql-query
Second, factory model
In real life, the factory is responsible for producing products, such as milk, bread or gifts, which meet our daily physiological needs.
Among the many design patterns, there is a design pattern called factory pattern, which provides the best way to create objects. Factory patterns can be divided into simple factory patterns, factory method patterns and abstract factory patterns.
2.1 simple Factory
The simple factory pattern is also called the static method pattern because a static method is defined in the factory class to create the object. Simple factory allows users to create the required "product" class without knowing the specific parameters, that is, users can consume the product directly without knowing the specific production details of the product.
In the picture above, brother Po simulates the process of buying a car. Xiao Wang and Xiao Qin order BMW730 and BMW840 models from the BMW factory respectively, and then the factory will first judge the model selected by the user, then produce it according to the corresponding model and deliver it to the user after the production is completed.
Let's take a look at how to use a simple factory to describe the process of producing a specified type of car in a BMW factory.
2.1.1 implementation code
Abstract class BMW {abstract run (): void;} class BMW730 extends BMW {run (): void {console.log ("BMW730 starts");}} class BMW840 extends BMW {run (): void {console.log ("BMW840 start");}} class BMWFactory {public static produceBMW (model: "730s" | "840s"): BMW {if (model = = "730s") {return new BMW730 () } else {return new BMW840 ();}
In the above code, we define a BMWFactory class that provides a static produceBMW () method for creating different models of cars based on different model parameters.
2.1.2 use examples
Const bmw730 = BMWFactory.produceBMW; const bmw840 = BMWFactory.produceBMW; bmw730.run (); bmw840.run ()
2.1.3 Application scenario
The factory class is responsible for creating fewer objects: because fewer objects are created, the business logic in the factory method is not too complex.
The client only needs to know the parameters of the static method passed into the factory class and does not need to care about the details of creating the object.
2.2 Factory method
Factory method pattern (Factory Method Pattern), also known as factory pattern, also known as polymorphic factory (Polymorphic Factory) pattern, belongs to the class creation pattern.
In the factory method pattern, the factory parent class is responsible for defining the public interface for creating product objects, while the factory subclass is responsible for generating specific product objects. The purpose of this is to defer the instantiation of the product class to the factory subclass, that is, to determine which specific product class should be instantiated through the factory subclass.
2.2.1 implementation code
Abstract class BMWFactory {abstract produceBMW (): BMW;} class BMW730Factory extends BMWFactory {produceBMW (): BMW {return new BMW730 ();}} class BMW840Factory extends BMWFactory {produceBMW (): BMW {return new BMW840 ();}}
In the above code, we create two factory classes, BMW730Factory and BMW840Factory, respectively, and then use the instances of these two classes to produce different models of cars.
2.2.2 use examples
Const bmw730Factory = new BMW730Factory (); const bmw840Factory = new BMW840Factory (); const bmw730 = bmw730Factory.produceBMW (); const bmw840 = bmw840Factory.produceBMW (); bmw730.run (); bmw840.run ()
2.2.3 Application scenario
A class does not know the class of the object it needs: in the factory method mode, the client does not need to know the class name of the specific product class, but only needs to know the corresponding factory, and the specific product object is created by the specific factory class; the client needs to know the factory class that creates the specific product.
A class specifies which object to create through its subclass: in the factory method pattern, the abstract factory class only needs to provide an interface to create the product, while its subclass determines the specific object to be created. using the object-oriented polymorphism and the principle of Richter substitution, when the program is running, the subclass object will overwrite the parent object, which makes the system easier to extend.
2.3 Abstract Factory
Abstract Factory pattern (Abstract Factory Pattern), which provides an interface for creating a series of related or interdependent objects without specifying their concrete classes.
In the factory method mode, a specific factory is responsible for producing specific products, and each specific factory corresponds to a specific product, and the factory method is also unique. In general, there is only one factory method or a set of overloaded factory methods in a specific factory. But sometimes we need a factory that can provide multiple product objects instead of a single product object.
2.3.1 implementation code
Abstract class BMWFactory {abstract produce730BMW (): BMW730; abstract produce840BMW (): BMW840;} class ConcreteBMWFactory extends BMWFactory {produce730BMW (): BMW730 {return new BMW730 ();} produce840BMW (): BMW840 {return new BMW840 ();}}
2.3.2 use examples
Const bmwFactory = new ConcreteBMWFactory (); const bmw730 = bmwFactory.produce730BMW (); const bmw840 = bmwFactory.produce840BMW (); bmw730.run (); bmw840.run ()
2.3.3 Application scenario
A system should not rely on the details of how product class instances are created, combined, and expressed, which is important for all types of factory patterns.
There is more than one product family in the system, and only one of them is used at a time.
The system provides a library of product classes, and all products appear with the same interface, so that the client does not depend on the specific implementation.
III. Singleton model
Singleton pattern (Singleton Pattern) is a common pattern, there are some objects we often only need one, such as the global cache, the window object in the browser, and so on. The singleton pattern is used to ensure that there is only one instance of a class and to provide a global access point to it.
In the picture above, Brother Ah Bao simulated the process of borrowing a car. Xiao Wang had an emergency to borrow a car from Brother A Bao. Brother A Bao's car happened to be useless, so he lent it to Xiao Wang. On the same day, Xiao Qin also needed a car and borrowed a car from Brother Ah Bao, because Brother Ah Bao had only one car at home, so there was no car to borrow.
For the car, although it brings great convenience to life, but the car also requires a large amount of money (parking fees, fuel and maintenance fees, etc.), so Brother Po has only one car at home.
When developing a software system, if we encounter objects that take too much time to create or consume too much resources, but are often used, we can consider using singleton patterns.
Let's take a look at how to implement the singleton pattern using TypeScript.
3.1 implementation code
Class Singleton {/ / defines private static properties to save the object instance private static singleton: Singleton; private constructor () {} / / provides a static method to get the object instance public static getInstance (): Singleton {if (! Singleton.singleton) {Singleton.singleton = new Singleton ();} return Singleton.singleton;}}
3.2 use examples
Let instance1 = Singleton.getInstance (); let instance2 = Singleton.getInstance (); console.log (instance1 = instance2); / / true
3.3 Application scenario
Objects that need to be frequently instantiated and then destroyed.
Objects that take too much time or resources to create, but are often used.
The system needs only one instance object, such as the system requires a unique serial number generator or resource manager, or needs to consider that the resource consumption is so high that only one object is allowed to be created.
IV. Adapter mode
In real life, there are also scenarios in which adapters are used, such as Hong Kong plug converters, power adapters and USB adapters. In software engineering, the function of adapter pattern is to solve the problem of incompatible interfaces between two software entities. After using the adapter pattern, two software entities that could not work because of interface incompatibility can work together.
4.1 implementation Code
Interface Logger {info (message: string): Promise;} interface CloudLogger {sendToServer (message: string, type: string): Promise;} class AliLogger implements CloudLogger {public async sendToServer (message: string, type: string): Promise {console.info (message); console.info ('This Message was saved with AliLogger');} class CloudLoggerAdapter implements Logger {protected cloudLogger: CloudLogger; constructor (cloudLogger: CloudLogger) {this.cloudLogger = cloudLogger } public async info (message: string): Promise {await this.cloudLogger.sendToServer (message, 'info');}} class NotificationService {protected logger: Logger; constructor (logger: Logger) {this.logger = logger;} public async send (message: string): Promise {await this.logger.info (`Notification sended: ${message} `);}}
In the above code, because the Logger and CloudLogger interfaces do not match, we introduced the CloudLoggerAdapter adapter to solve the compatibility issue.
4.2 use examples
(async () = > {const aliLogger = new AliLogger (); const cloudLoggerAdapter = new CloudLoggerAdapter (aliLogger); const notificationService = new NotificationService (cloudLoggerAdapter); await notificationService.send ('Hello semlinker, To Cloud');}) ()
4.3 Application scenarios and cases
The previously developed system has classes that meet the functional requirements of the new system, but its interface is not consistent with that of the new system.
Use components provided by third parties, but the component interface definition is different from the interface definition required by yourself.
Github-axios-mock-adapter: https://github.com/ctimmerm/axios-mock-adapter
Observer model & publish and subscribe model
5.1 Observer mode
Observer pattern, which defines an one-to-many relationship, allows multiple observer objects to listen to a topic object at the same time, and notifies all observer objects when the state of the subject object changes, so that they can update themselves automatically.
There are two main roles in observer mode: Subject (subject) and Observer (observer).
In the picture above, Subject (theme) is brother Po's TS feature article, and the observers are Xiao Qin and Xiao Wang. Because the observer mode supports simple broadcast communication, all observers are automatically notified when the message is updated.
Let's take a look at how to use TypeScript to implement the observer pattern.
5.1.1 implementation code
Interface Observer {notify: Function;} class ConcreteObserver implements Observer {constructor (private name: string) {} notify () {console.log (`${this.name} has been notified.`);} class Subject {private observers: Observer [] = []; public addObserver (observer: Observer): void {console.log (observer, "is pushed!"); this.observers.push (observer) } public deleteObserver (observer: Observer): void {console.log ("remove", observer); const n: number = this.observers.indexOf (observer); n! =-1 & & this.observers.splice (n, 1);} public notifyObservers (): void {console.log ("notify all the observers", this.observers); this.observers.forEach (observer = > observer.notify ());}}
5.1.2 examples of use
Const subject: Subject = new Subject (); const xiaoQin = new ConcreteObserver (Xiao Qin); const xiaoWang = new ConcreteObserver (Xiao Wang); subject.addObserver (xiaoQin); subject.addObserver (xiaoWang); subject.notifyObservers (); subject.deleteObserver (xiaoQin); subject.notifyObservers ()
5.1.3 Application scenarios and cases
The behavior of one object depends on the state of another object. Or to put it another way, when the state of the observed object (target object) changes, it will directly affect the behavior of the observed object.
RxJS Subject: https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts
RxJS Subject documents: https://rxjs.dev/guide/subject
5.2 publish and subscribe model
In software architecture, publish / subscribe is a message paradigm, and the sender (called publisher) of the message does not send the message directly to a specific receiver (called subscriber). Instead, the published messages are divided into different categories and then sent to different subscribers. Similarly, subscribers can express interest in one or more categories and receive only messages of interest without knowing which publishers exist.
There are three main roles in the publish-subscribe model: Publisher (publisher), Channels (channel), and Subscriber (subscriber).
In the picture above, Publisher (publisher) is Po Brother, Topic An and Topic B in Channels (Channel) correspond to TS and Deno topics respectively, and Subscriber (subscribers) are Xiao Qin, Xiao Wang and Xiao Chi.
Let's take a look at how to use TypeScript to implement the publish and subscribe model.
5.2.1 implementation code
Type EventHandler = (... args: any []) = > any; class EventEmitter {private c = new Map (); / / subscribe to the specified topic subscribe (topic: string,... handlers: EventHandler []) {let topics = this.c.get (topic); if (! topics) {this.c.set (topic, topics = []);} topics.push (... handlers) } / / Unsubscribe to the specified topic unsubscribe (topic: string, handler?: EventHandler): boolean {if (! handler) {return this.c.delete (topic);} const topics = this.c.get (topic); if (! topics) {return false;} const index = topics.indexOf (handler); if (index
< 0) { return false; } topics.splice(index, 1); if (topics.length === 0) { this.c.delete(topic); } return true; } // 为指定的主题发布消息 publish(topic: string, ...args: any[]): any[] | null { const topics = this.c.get(topic); if (!topics) { return null; } return topics.map(handler =>{try {return handler (.. ARGs);} catch (e) {console.error (e); return null;}});}}
5.2.2 use examples
Const eventEmitter = new EventEmitter (); eventEmitter.subscribe ("ts", (msg) = > console.log (`messages received from subscriptions: ${msg} `); eventEmitter.publish ("ts", "TypeScript publish / subscribe model"); eventEmitter.unsubscribe ("ts"); eventEmitter.publish ("ts", "TypeScript publish / subscribe model")
5.2.3 Application scenario
There is an one-to-many relationship between objects, and a change in the state of one object will affect other objects.
As an event bus, to realize the communication between different components or modules.
BetterScroll-EventEmitter: https://github.com/ustbhuangyi/better-scroll/blob/dev/packages/shared-utils/src/events.ts
Application of EventEmitter in plug-in Architecture: https://mp.weixin.qq.com/s/N4iw3bi0bxJ57J8EAp5ctQ
VI. Strategic model
Policy pattern (Strategy Pattern) defines a series of algorithms, encapsulates them one by one, and makes them interchangeable. The focus of the strategy pattern is not how to implement algorithms, but how to organize and invoke these algorithms, so as to make the program structure more flexible, maintainable and extensible.
At present, many different login methods are provided in some mainstream Web sites. Such as account password login, mobile CAPTCHA login and third-party login. In order to facilitate the maintenance of different login methods, we can encapsulate different login methods into different login policies.
Let's take a look at how to use policy mode to encapsulate different login methods.
6.1 implementation code
To better understand the following code, let's take a look at the corresponding UML class diagram:
Interface Strategy {authenticate (... args: any): any;} class Authenticator {strategy: any; constructor () {this.strategy = null;} setStrategy (strategy: any) {this.strategy = strategy;} authenticate (. Args: any) {if (! this.strategy) {console.log ('authentication policy not set'); return;} return this.strategy.authenticate (. Args) }} class WechatStrategy implements Strategy {authenticate (wechatToken: string) {if (wechatToken! = = '123') {console.log (' invalid Wechat user'); return;} console.log ('Wechat authentication successful') }} class LocalStrategy implements Strategy {authenticate (username: string, password: string) {if (username! = = 'abao' & & password! =' 123') {console.log ('account or password error'); return;} console.log ('account and password authentication successful');}}
6.2 examples of use
Const auth = new Authenticator (); auth.setStrategy (new WechatStrategy ()); auth.authenticate ('123456'); auth.setStrategy (new LocalStrategy ()); auth.authenticate (' abao', '123')
6.3 Application scenarios and cases
When a system needs to dynamically select one of several algorithms, each algorithm can be encapsulated into a policy class.
Multiple classes differ only in expressing behavior, and you can use the policy pattern to dynamically select the specific behavior to be executed at run time.
A class defines multiple behaviors, and these behaviors appear in the form of multiple conditional statements in the operation of this class, and each conditional branch can be moved into its own policy class to replace these conditional statements.
Github-passport-local: https://github.com/jaredhanson/passport-local
Github-passport-oauth3: https://github.com/jaredhanson/passport-oauth3
Github-zod: https://github.com/vriad/zod/blob/master/src/types/string.ts
VII. Duty chain model
The responsibility chain pattern is to make multiple objects have the opportunity to process the request, thus avoiding the coupling relationship between the sender and receiver of the request. In the on-the-job responsibility chain model, many objects are connected by each object's reference to its next family to form a chain. The request is passed on the chain until an object on the chain decides to process the request.
7.1 implementation Code
To better understand the following code, let's take a look at the corresponding UML class diagram:
Interface IHandler {addMiddleware (h: IHandler): IHandler; get (url: string, callback: (data: any) = > void): void;} abstract class AbstractHandler implements IHandler {next extents: IHandler; addMiddleware (h: IHandler) {this.next = h; return this.next;} get (url: string, callback: (data: any) = > void) {if (this.next) {return this.next.get (url, callback) } / / define Auth middleware class Auth extends AbstractHandler {isAuthenticated: boolean; constructor (username: string, password: string) {super (); this.isAuthenticated = false; if (username = = 'abao' & & password =' 123') {this.isAuthenticated = true }} get (url: string, callback: (data: any) = > void) {if (this.isAuthenticated) {return super.get (url, callback);} else {throw new Error ('Not Authorized');} / / define Logger middleware class Logger extends AbstractHandler {get (url: string, callback: (data: any) = > void) {console.log (' / GET Request to:', url) Return super.get (url, callback);} class Route extends AbstractHandler {URLMaps: {[key: string]: any}; constructor () {super (); this.URLMaps = {'/ api/todos': [{title: 'learn ts'}, {title:' learn react'}],'/ api/random': Math.random (),} } get (url: string, callback: (data: any) = > void) {super.get (url, callback); if (this.URLMaps.hasOwnProperty (url)) {callback (this.URLMaps [url]);}
7.2 examples of use
Const route = new Route (); route.addMiddleware (new Auth ('abao',' 123')) .addMiddling (new Logger ()); route.get ('/ api/todos', data = > {console.log (JSON.stringify ({data}, null, 2));}); route.get ('/ api/random', data = > {console.log (data);})
7.3 Application scenario
A collection of objects that can handle a request should be specified dynamically.
You want to submit a request to one of multiple objects without explicitly specifying the recipient.
There are multiple objects that can process a request, and which object handles the request is automatically determined by the runtime, and the client only needs to submit the request to the chain.
VIII. Template method model
The template method pattern consists of two parts: the abstract parent class and the concrete implementation subclass. The algorithm framework of the subclass is usually encapsulated in the abstract parent class, including the implementation of some common methods and the execution order of all methods in the subclass. By inheriting this abstract class, the subclass also inherits the entire algorithm structure, and can choose to override the methods of the parent class.
8.1 implementation code
To better understand the following code, let's take a look at the corresponding UML class diagram:
Import fs from 'fs'; abstract class DataParser {data: string =''; out: any = null; / / this is the so-called template method parse (pathUrl: string) {this.readFile (pathUrl); this.doParsing (); this.printData ();} readFile (pathUrl: string) {this.data = fs.readFileSync (pathUrl, 'utf8');} abstract doParsing (): void PrintData () {console.log (this.out);} class CSVParser extends DataParser {doParsing () {this.out = this.data.split (',');}} class MarkupParser extends DataParser {doParsing () {this.out = this.data.match (/. * / gim);}}
8.2 examples of use
Const csvPath ='. / data.csv'; const mdPath ='. / design-pattern.md'; new CSVParser () .parse (csvPath); new MarkupParser () .parse (mdPath)
8.3 Application scenario
The overall step of the algorithm is very fixed, but when some parts of the algorithm are changeable, the template method pattern can be used to abstract the easily changed parts for subclass implementation.
When you need to control the extension of a subclass, the template method only invokes the hook operation at a specific point, which allows the extension only at those points.
Thank you for your reading, the above is the content of "what are the common design patterns"? after the study of this article, I believe you have a deeper understanding of the common design patterns. The specific use of the situation also needs to be verified by practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.