What are design patterns

In the rookie tutorial, it is defined like this:

Design patterns represent best practices and are generally adopted by experienced object-oriented software developers. Design pattern is a solution to the common problems faced by software developers during software development. These solutions have been developed by numerous software developers over a long period of trial and error.

A design pattern is a set of repeated, well-known, catalogued code design lessons. Design patterns are used to reuse code, make it easier for others to understand, and ensure code reliability. There is no doubt that design patterns are a win-win for yourself, others and systems. Design patterns make coding truly engineering. Design patterns are the cornerstones of software engineering, like the bricks and stones of a mansion. The rational application of design patterns in projects can perfectly solve many problems. Each pattern has its corresponding principle in reality, and each pattern describes a recurring problem around us, as well as the core solution of the problem, which is also the reason why design patterns can be widely used.

I only have one word to describe design patterns: routines.

Personal understanding: Design patterns are basic routines for solving problems frequently encountered in software engineering. So what are the benefits of using these routines? Ask the reader to think for two minutes.

Why use design patterns

Those of you who have studied software engineering surely know that there is a concept in software engineering called high cohesion and low coupling, which is the criterion for judging the quality of software design. Its purpose is to improve the reusability and portability of program modules. In general, the higher the cohesion between modules, the lower the coupling between modules. This all sounds abstract, but let me give you a concrete example to give you an idea of the importance of high cohesion and low coupling.

The customer asked me to build a background management system, but it requires different permissions. Its main function is to add, delete, change and check. Then I immediately thought of using tables to display data.

User roughly six kinds of roles, each role has 80% of the content is the same, 20% of the content is determined based on the role authorization, I first of all, the lowest level of the user management page made out, then a CV made six pages, and then in the specific page specific fields and functions, a month to finished it, I would show my system to the client with satisfaction, and then the client would tell me where I was missing a field in the table, where I was missing a search function, where I was missing a sorting function, where the modification function was not very friendly, and then I did not delete it. No way, who called party A is the father, in order to get the money, I can only go back to change.

Change the code, I found a good CD (beautiful Chinese), a change over again to five, then feel the code with “excrement mountain”, one by one to find where is the CV, and at that time, our project is a collaboration of two people, is in accordance with the page, and then found out some change, some didn’t change, the effect of the changes is different also, The most ridiculous thing was that the functionality of this page was added to another page, and I was thinking, good thing it was 6 pages, not 60 pages, or I would have died on the spot. At that time, I thought, if only we could pull out the table component at the beginning of the project, expose some excuses, and change the actual content by modifying the properties of the table component when referencing it.

This is the author’s own experience, and in fact I remember more than 6 pages, are the lessons of tears, from then on, I think reusable things must be encapsulated, or later maintenance is a pile of “shit mountain” waiting for you.

In fact, one of the primary purposes of using design patterns is decoupling. Let’s look at a few concrete examples of using design patterns.

The strategy pattern

Definition: Define a set of algorithms, encapsulate them one by one, and make them interchangeable.

The purpose of the policy pattern is to decouple algorithm usage from algorithm implementation.

A program based on the policy pattern has at least two parts. The first part is a set of policies (variables) that encapsulate the specific algorithm, the implementation of the algorithm described above. The second part is the environment class Context (unchanged), which receives the client’s request and then delegates it to a policy class. To do this, a reference to a policy object is maintained in the Context.

Let’s look at a practical example where year-end bonuses are given based on the user’s level and salary.

Not using policy mode:

const calculateBonus = (level,salary) = > {
  switch(level){
    case 's': {return salary*4
    }
    case 'a': {return salary*3
    }
    case 'b': {return salary*2
    }
    default: {return 0
    }
  }
  
}

calculateBonus('s'.20000)
calculateBonus('a'.10000)
Copy the code

You can see that the implementation of the algorithm and the call of the algorithm are coupled together, which has two disadvantages, one is not conducive to reading comprehension, but is not conducive to maintenance. Let’s look at the code after using the policy pattern:

/ / strategy
const strategies = {
  s: (salary) = > salary * 4.a: (salary) = > salary * 3.b: (salary) = > salary * 2};/ / environment
const calculateBonus = (level, salary) = > strategies[level](salary);

calculateBonus("s".20000);		
calculateBonus("a".10000);
Copy the code

You can see that we have removed the strategy class, so that when there is a new year-end bonus algorithm in the future we can just add attributes to the strategy class without changing our environment class.

By contrast, is the following code easier to understand and maintain?

Publish and subscribe model

Application scenarios

This design pattern is, I think, the most widely used pattern in the world today.

At this time there must be readers have questions, how do you say this? Don’t worry, just listen to me.

Have you ever used Sina Weibo? Have you used station B? Have you ever used QQ Zone? If you haven’t used wechat moments before, you probably have.

Almost 99 percent of all social platforms currently use this model.

Let’s take Sina Weibo as an example. As an ordinary user, we will follow some big V’s or interesting bloggers. This process is called subscribe. Then one day, the star you follow publishes a post on weibo: “publish”. Then you receive a notice. The XXX you follow publishes a post on Weibo, which is called notify. And then you click on it, and you realize that it’s someone you hate, and then you get angry, and you lose your fan, and you unsubscribe, and this process is called unsubscribe.

Observer model

The four core actions of publish and subscribe mode have been explained here. In fact, there are two objects involved, one is observer (in this case, we as fans), and the other is subject (in this case, stars you follow). In fact, there are many people who believe that the publish-subscribe model is an improved version of the observer model. The observer pattern is that an object maintains a series of objects (observers) that depend on it and actively notifies those observers of changes in the object’s state.

class Subject {
  constructor() {
    this.observers = [];
  }

  // Collect dependencies
  add(observer) {
    this.observers.push(observer);
  }

  // Delete dependencies
  remove(observer) {
    const index = this.observers.indexOf(observer);
    if(index ! = = -1) {
      this.observers.splice(index, 1); }}// Notify the observer of the update
  notify() {
    this.observers.forEach((observer) = > observer.update());
  }

  // Returns a copy of the observer list
  getObservers() {
    return[...this.observers]; }}class Observer {
  // Update operation
  update(){}}Copy the code

Promise uses this design pattern, collecting callback functions (an observer of an Update function) into a microtask queue in the prototype method THEN, and notifies the corresponding callback execution when it executes resolve or Reject when its state changes.

code

Talk is cheap, show me the code. Let’s write a simple PubSub class.

class Publisher {
  constructor(id, name) {
    this.id = id;
    this.name = name; }}class Subscriber {
  constructor(id, name) {
    this.id = id;
    this.name = name;
  }
  // Update operation
  update(publisher, data) {
    console.log(publisher.name + "New content released:"+ data); }}class PubSub {
  constructor() {
    // Event control center
    this.pubsub = {};
  }

  / * * *@description Publish action@param {object} Publisher *@param {object} Data publishes content */
  publish(publisher, data) {
    const subscribers = this.pubsub[publisher.id];
    if(! subscribers || ! subscribers.length)return;
    subscribers.forEach((subscriber) = > subscriber.update(publisher, data));
  }

  / * * *@description Subscribe action *@param {obejct} Publisher *@param {object} Subscriber subscriber */
  subscribe(publisher, subscriber) {
    // Initializes the array if the publisher has no subscribers
    !this.pubsub[publisher.id] && (this.pubsub[publisher.id] = []);

    // Put the subscriber object into the event scheduler
    this.pubsub[publisher.id].push(subscriber);
  }

  / * * *@description Unsubscribe *@param {object} Subscriber subscriber *@param {object} Publisher */
  unsubscribe(publisher, subscriber) {
    const index = this.pubsub[publisher.id].findIndex(
      (sub) = > sub.id === subscriber.id
    );
    if(index ! = = -1) this.pubsub[publisher.id].splice(index, 1); }}// Simple test
const wzq = new Subscriber(Awesome!."wzq");
const yxy = new Publisher(99."Evan You");
const pubSub = new PubSub(); // The singleton pattern is recommended here to create objects
pubSub.subscribe(yxy, wzq);
pubSub.publish(yxy, "Vue 3.2 official release");
pubSub.unsubscribe(yxy, wzq);
pubSub.publish(yxy, "Vue 4.0 will be released in January 2022"); // No output

Copy the code

Comparing the above two codes, it is easy to see that the disadvantage of observer mode is that the observed object must maintain a list of observers. When the status of the object is updated, the observer update method is directly called. And release a subscription model have a event dispatching center (some call it also pipe), it maintains a hash table, the key is that every publisher id, its value is to subscribe to this publisher subscriber collection (real scenario could be a set of id), which makes the publisher and subscribers are not direct interaction, avoids the subscribers and publishers have dependencies. Publishers publish their content through the event scheduling center and then trigger the corresponding subscribers to perform updates.

To be continued…