preface

This paper is to share the related content about design patterns, the design pattern, we should not strange, like singleton, publish-subscribe, factory design pattern should be very familiar with, you should also know how to do this a few common design pattern, after all, an interview will often be asked, but they may not be in the project development application design patterns, If else, for cycle a shuttle, still can run the project, but it is also easy to bring certain difficulties to the later iteration, expansion and so on because of design defects, many places unreasonable. This kind of code to write more, for their own growth is not too much help, more is repeating, people always have to grow a little. Understanding design patterns will help you improve your code design skills, and you will have more contacts and think more broadly.

For most of the students, the design pattern may just be regarded as a theoretical knowledge of the interview will be used in the eight-part essay. Yes, compared to before, I also look at the design mode in this way, for me, the design mode is mountain, water is water, mountain is not mountain, water is not water, in short, I feel unfathomable, but can not use, just stay in the impression, as if there is such a thing. With the accumulation of work experience and the increase of business contact, we need to think about how to write robust and extensible code and design a reasonable code structure. Design patterns are a good way to go, and their proper application can help us make better code design and provide more ideas for solving problems.

For example,

Before I share a common design pattern with you, LET me introduce a common design pattern in its application.

You should be familiar with the above picture, which is the MVC architecture we often use in projects. The DESIGN of MVC architecture itself is a combination of multiple design patterns, mainly generated by the application of the three design patterns: composite pattern, policy pattern and observer (or publish and subscribe pattern). Here is a brief description of how these three design patterns are applied in the MVC architecture:

MVC: Model (data model), View (view), controller(controller). The purpose of MVC architecture design is to separate the view interface from the business logic, so as to achieve the extensibility, reusability, maintainability of the code, and reduce the corresponding degree of business coupling.

View layer, itself to achieve the combination pattern, the combination pattern of objects into a tree structure, to express the “partial-whole” hierarchy, that is to say, the structure of the combination pattern is a tree structure, and the HTML page structure itself is a tree structure, this should be the application of the combination pattern, but we do not perceive, The browser does this for us. In our business, composite patterns can also solve some problems, such as optimization to handle recursion, most tree structure problems can be handled recursively, we can also try to think whether we can use composite patterns to solve problems.

In MVC, View and Model are the relationship between observer and observed, that is, two roles in the observer mode: observer and observed. When the model changes, the View will be notified to update the corresponding view, but there is no direct correlation between the Model and the View. When the data in the Model changes, the Model does not need to actively push the message of the data change to the View, but to be processed by the controller. Changes in the Model layer are usually caused by user actions, which are handled by the Controller. When the Controller changes the Model, it is the Controller that sends the updated information to the View. To some extent, it’s more about publishing subscriptions. The publish-subscribe model and the Observer model share the same core idea.

The application of policy mode is mainly in view and controller. View and Controller have a one-to-many relationship. Controller is a strategy of view, and controller can be replaced for view.

Many large projects, including many Web projects, adopt or borrow MVC architecture ideas. When you are familiar with the application of design patterns, you will find that architectural design is actually a combination of many design patterns. Architectural design is not very mysterious, nor is it out of reach. The application of design pattern is quite common in projects. Sometimes, I cannot understand the project architecture or know how to design the code more rationally. I may have too narrow contact area, which limits my thinking.

Wrote so many, haven’t specifically design patterns related content, to express the content of the above purpose is that we can try to think in real business design pattern, MVC architecture is one of the most common way of architecture project, we may be the main concern in its application: how do we use this architecture, the architecture can solve any problem. You may not think in terms of architecture, how the architecture is built, how design patterns are applied to the architecture. Yes, I have not thought about these problems, now we need to think about these problems, think more about the things behind the framework, the Eight-part essay may not be eight-part essay. It’s hard to think about this stuff, and I’m not so good at reading and learning anymore.

Design Pattern definition

A design pattern is a concise and elegant solution to a particular problem in object-oriented software design. In human terms, a design pattern is a solution to a problem in a situation. It is not a language syntax, but a summary of the code development experience of the industry’s bigwigs, applicable to all languages. We can think of design patterns as a series of templates to solve a particular problem, that is, design patterns can be applied.

Design pattern is summed up to help us quickly solve some problems in the program design, such as object creation, communication between objects, object function expansion and so on, the solution of these problems we can be summed up in the design pattern to find solutions. But in the actual development, we also need to make choices according to the actual needs. If it is a simple program, it may be easier to write a simple code than to introduce a certain design pattern. Do not over-design. For large projects or framework designs, such as the MVC architecture, it is clearly better to organize your code with design patterns.

object-oriented

Design mode is proposed based on object-oriented, we use design mode should not be divorced from the object-oriented premise, so we understand the various design modes before we should understand the idea of object-oriented, the essence of design mode is the practical application of five object-oriented design principles, It is a full understanding of the encapsulation, inheritance and polymorphism of classes as well as the associative and combinative relations of classes.

Object – oriented three features: encapsulation, inheritance, polymorphism.

Five principles of object-oriented design: open and close principle, Richter’s substitution principle, dependence inversion principle, single responsibility principle, interface isolation principle.

Of object-oriented concepts should have knowledge and application, but should also have a classmate and the characteristic of object-oriented design principle is not very familiar with, I recommend before contact with design patterns, features and design principles of object-oriented first have a full understanding, to the understanding of the design pattern there will be a big help, Design patterns themselves apply one or more of the object-oriented features and design principles, so when you understand the object-oriented features and design principles, design patterns are very simple things, there is no magic.

Instead of describing object-oriented features and design principles in detail, I encourage you to take a look at them, and I’ll describe what features and design principles apply to the specific design pattern.

Here are some of the most common design patterns I use: singleton, factory, policy, publish and subscribe.

The singleton pattern

Global variables, I think you’ve all used them, they’re very useful. Define global variables, projects can be used everywhere, although good, but the disadvantages are also very obvious, javaScript such a weakly typed language, variables and methods are exposed in the global, it is easy to appear variable conflicts, variables will be overwritten risk, should try to avoid using global variables. The singleton pattern solves this problem.

define

A class that has only one instance and provides a global access point to access it. Simply put, a class can create only one instance, and even if multiple instances are created, they are all the same. There is no overwriting problem, only one instance is guaranteed, and global access is provided.

The instance singleton pattern has two main ways of creating class instances through static methods of the class, and creating class instances through the new operator.

A static method

class Singleton {
    constructor() {
        this.name = 'singleton';
    }
    static getInstance() {
      if(! Singleton.instance) { Singleton.instance =new Singleton();
      }
      returnSingleton.instance; }}let instance1 = Singleton.getInstance();
let instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
Copy the code

By static method to create a class instance, not enough transparent, because it is through the static method to create instances of classes, constrain the instantiation of call way, increased the use cost, for the user’s need to read the code just know this class is a singleton class, need by calling a static method to create a class instance, otherwise will still by the new operator to create a class instance, This loses the value of the singleton and is of little practical significance.

The degree of coupling is too high to conform to the object-oriented single responsibility principle, singleton maintenance and object creation are coupled together.

newThe operator

class Singleton {
    constructor() {
        if (Singleton.instance) {
          return Singleton.instance;
        }
        Singleton.instance = this;
        this.name = 'singleton'; }}let instance1 = new Singleton();
let instance2 = new Singleton();
console.log(instance1 === instance2); // true
Copy the code

Creating class instances through the new operator solves the problem that static methods are not transparent enough, but the coupling degree is still too high, which does not conform to the principle of object-oriented single responsibility. Singleton maintenance and object creation are coupled together.

Proxy mode

/ / business class
class CreateSingleton {
    constructor() {
        this.name = 'singleton'; }}/ / the singleton class
class Singleton {
    constructor(Target, ... args) {
        if(! Target.instance) { Target.instance =newTarget(... args); }returnTarget.instance; }}let instance1 = new Singleton(CreateSingleton);
let instance2 = new Singleton(CreateSingleton);
console.log(instance1 === instance2); // true
Copy the code

Directly by acting the way to solve the static method and the new operator to create a singleton class instance, a “single responsibility principle” in line with the object oriented, different objects with independent responsibility, not too tightly coupled, the responsibility of the business class is only responsible for the class itself, singleton classes are only responsible for creating business class singletons, specific executive function or the object of ontology. Through the proxy method, the service decoupling is better achieved.

At the same time, the common instance objects in the proxy mode also follow the object-oriented “dependency inversion principle”. The instance of CreateSingleton is created by dependency injection, which avoids the strong correlation between the singleton class and the singleton class, and realizes the universality of the singleton class. Singleton objects of different business classes can be created. Improved code extensibility and easy maintenance.

The proxy mode realizes singleton mode through proxy mode, and the creation of singleton object is the combination of proxy mode and singleton mode.

Classic application

Vuex, you should be familiar with the state management mode of VUE, which uses centralized storage to manage the state of all components of the application, uses a global Store to Store the state of the application, and provides API for users to do read and write operations. Different pages can access the Store object and obtain the same value, which enables data synchronization between different pages. It is essentially implemented through the singleton pattern. The vuEX implementation is a classic application of the singleton pattern.

Let’s look at the implementation of VUex:

// main.js
import Vue from 'vue';
import Vuex from 'vuex';
import store from './store';
Vue.use(Vuex); // Install vuex plug-in
new Vue({
    store, // Store is injected into the Vue instance
    el: '#app'});Copy the code

Vuex plug-in is installed by vuue.use () method (this method conforms to the principle of dependency inversion. Vuex object is injected into VUE through dependency injection, which reduces the coupling degree between vue main body and Vuex). Let’s first look at vue.use () implementation:

// vue/src/core/global-api/use.js
export function initUse (Vue: GlobalAPI) {
    // Accept a plugin argument that can be Function or Object
    Vue.use = function (plugin: Function | Object) {
        const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
        // Check whether the plug-in is registered to prevent repeated registration
        if (installedPlugins.indexOf(plugin) > -1) {
            return this
        }

        // additional parameters
        const args = toArray(arguments.1)
        args.unshift(this)
        // Execute the install method, passing in Vue as an instance
        if (typeof plugin.install === 'function') { // plugin is the object that executes the built-in install method
            plugin.install.apply(plugin, args)
        } else if (typeof plugin === 'function') { // plugin is a function that is used as the install method
            plugin.apply(null, args)
        }
        // Record that plugin is registered
        installedPlugins.push(plugin)
        return this}}Copy the code

Vue.use() essentially executes the install method of the plug-in, which is customized by the plug-in and is installed in advance of Vue instantiation.

Let’s take a look at the Vuex plugin’s install implementation:

// vuex/src/store.js
let Vue; // bind on install.export function install (_Vue) {
  Use (Vuex) has been executed. If the Vuex has been executed for several times in a non-production environment, an error message is displayed
  if (Vue && _Vue === Vue) {
    if(process.env.NODE_ENV ! = ='production') {
      console.error(
        '[vuex] already installed. Vue.use(Vuex) should be called only once.')}return
  }
  // If it is the first time vue.use (Vuex) is executed, the _Vue passed in is assigned to the defined variable Vue
  Vue = _Vue
  // Vuex initialization logic
  applyMixin(Vue)
}
Copy the code

When vuue. Use (Vuex) is executed, the install method is essentially executed. Vue is passed in as a parameter, and Vue objects are cached using the variable Vue. ApplyMixin (Vue) is also executed only once, meaning that there is only one copy of the Store globally. This is the implementation of Vuex’s singleton pattern.

Singleton rather easy to use, but don’t abuse, like Vuex is a singleton, don’t abuse Vuex in project, because Vuex can be global operating various changes, if the project is more collaborative development, is easy to many people at the same time to modify the data of Vuex, everybody has the authority to modify Vuex, it is easy to cause problems, We need to avoid using global operations as much as possible, and if we must use global operation data, we need to have a good project development specification.

The factory pattern

The factory pattern is also a creative design pattern. It is also a common design pattern. Most of you have probably used or heard of the factory pattern. Have you ever thought about this question, why do you use the factory model?

Now consider the following scenario: User A only has the view function on the system, while user B has the view, add, and delete functions on the system. Different roles have different permissions. How to handle this scenario? Let’s take a look at a more common approach:

class UserA {
    constructor(name){
        this.name = name;
        this.skills = ['look at'];
    }
    getName() {
        return this.name; }}class UserB {
    constructor(name){
        this.name = name;
        this.skills = ['look at'.'new'.'delete'];
    }
    getName() {
        return this.name; }}let userA = new UserA(Small 'a');
let userB = new UserB('the little b');
Copy the code

Explain from the above example: For only view the functions such as users, we define a UserA class, for a view, add, delete, and other functions of the user, we define a UserB, when we are in business application, if a user belongs to determine UserA class of users, we can create the user object, through instantiation UserA If a user belongs to UserB, instantiate UserB to create an object for this user. This treatment, obviously can also achieve the function, but this treatment is not unreasonable place??

The System class instantiates the UserA class in the new way. The association between the System class and the UserA class is generated, which leads to the coupling of the business. In the later stage, the instantiation method of the UserA class needs to be modified and the number of input parameters needs to be increased. So the UserA class needs to be modified, and the System class also needs to be modified. Since the UserA class needs to be modified, the UserB class also needs to be modified. If multiple classes depend on the UserA class and UserB class, the modification will be a huge amount of work, and it is also prone to error, and there is a high possibility of bugs. This code is extremely unmaintainable and coupled.

The UserA and UserB classes have very similar functional behavior except that their skills values are different. There is no need to create different role users with multiple classes because the code repetition rate is too high.

We need to separate the invocation and creation of objects. Instead of directly creating instance objects of User class in the System class, we can isolate them in some way, throw unified interfaces externally, and create various role objects internally. The business side does not care about the creation of related objects, only responsible for the invocation.

Factory mode can solve the above problem, the factory manages the object creation logic, the caller does not care about the specific creation process, only responsible for the call, through the input parameter to decide which object to use. The factory mode achieves the decoupling of related business well, and the object instantiation work is concentrated in one place, which reduces the code repetition rate and error rate.

Here, we should be more clear about the general application scenario of factory mode, also know what kind of problems can be solved, let’s look at the factory mode specifically how to define and use:

define

From the application layer, a factory is a function that is thrown out for use. The object creation logic is encapsulated in this function, without exposing the specific logic used to create the object. Simply put, the factory creates the object and uses it through function calls. The goal is to separate object creation from use.

According to the case business scenarios, factory patterns can be divided into three types: simple factory pattern, factory method pattern and abstract factory pattern. The simple factory pattern is commonly used.

Simple Factory model

In the simple factory pattern, also known as the static factory pattern, the method for creating instances is usually static (or not static, just a formality). The simple factory pattern has a concrete factory class that can generate multiple different products, the creation of which is done by the factory class itself:

// Character constants
const ROLE = {
    USER: 'user'.ADMIN: 'admin',}// user user class
class User {
    constructor(options) {
        let { role, name, skills } = options;
        this.role = role;
        this.name = name;
        this.skills = skills;
    }
    show() {
        console.log(`The ${this.name}The user has the following functions:The ${this.skills.join(', ')}`); }}// Simple factory class
class SimpleUserFactory {
    // Static methods to create different user objects
    static create(options, Target) {
        let { role } = options;
        switch (role) {
            case ROLE.USER:
                return new Target({
                    skills: ['look at'],
                    ...options,
                });
                break;
            case ROLE.ADMIN:
                return new Target({
                    skills: ['look at'.'new'.'delete'],
                    ...options,
                });
                break;
            default:
                break; }}}// Use the user
let userA = SimpleUserFactory.create({role: 'user'.name: 'white'}, User);
userA.show();
let userB = SimpleUserFactory.create({role: 'admin'.name: 'xiao li'}, User);
userB.show();
Copy the code

SimpleUserFactory is a simple factory. Two user objects have different functions. Use roles to identify users with different behaviors and then obtain instance objects of the object. It is also possible to pass in common field data (for example, the name field) as an argument.

The simple factory model also has disadvantages. If the factory method needs to be modified when new products are added, the code will become very bloated, which violates the object-oriented “open and close principle”. Moreover, the factory class is single, and one factory class can only create the same type of products. If you need to add other types of products, you need to add a specific factory class and the corresponding specific product class.

Factory method pattern

The factory method pattern is a further abstraction of the simple factory pattern, postponing the actual creation of objects to subclasses. The core class is abstract, so SimpleUserFactory is responsible for creating objects. This follows the “open close principle”. The essence of this is the use of inheritance.

// Character constants
const ROLE = {
    USER: 'user'.ADMIN: 'admin',}// User product class
class User {
    constructor(options) {
        let { role, name, skills } = options;
        this.role = role;
        this.name = name;
        this.skills = skills;
    }
    show() {
        console.log(`The ${this.name}The user has the following functions:The ${this.skills.join(', ')}`); }}// Abstract factory class
class AbstractSimpleUserFactory {
    constructor() {
        throw new Error('Abstract class cannot be instantiated');
    }
    admin((options, Target) {
       return new Target({
           skills: ['look at'.'new'.'delete'],
           ...options,
       });
    }
    user((options, Target) {
        return new Target({
           skills: ['look at'],... options, }); }}// Specific factory class
class SimpleUserFactory extends AbstractSimpleUserFactory {
    constructor() {
        super(a); }static create(options, Target) {
        let { role } = options;
        this[role](); }}let userA = SimpleUserFactory.create({role: 'user'.name: 'white'}, User);
userA.show();
let userB = SimpleUserFactory.create({role: 'admin'.name: 'xiao li'}, User);
userB.show();
Copy the code

The example above is the application of factory method pattern, SimpleUserFactory class only responsible for the actual object the creation of a new product to AbstractSimpleUserFactory class, to a certain extent SimpleUserFactory class follows the “open closed principle”.

Abstract Factory pattern

Simple factory pattern and factory method pattern is essentially factory directly generated instance objects, a single factory class can only create the same kind product, if you need new categories products, need new factory class to create a new class of product object, does not have versatility, the abstract factory pattern does not directly generate examples, it produces concrete factory, and then have a factory to create the corresponding specific product categories. I will not introduce the abstract factory pattern here, because I don’t use it much in business.

To some extent, factory mode can solve the creation and use of some objects, but not all objects are suitable for the creation of factory mode. Factory mode is more suitable for the creation of complex objects and the generation of a certain kind of objects. But many objects are relatively simple objects that don’t require as much business logic to create. Simple objects are used in many places, and if you need to modify the constructor parameters later, you will still have to address the problem from the beginning. A common solution is needed to handle object creation and use, and a common solution is described below.

Create a pattern summary

The singleton pattern, the factory pattern are the creator pattern, as well as the Builder pattern and the prototype pattern. The main focus of the creation mode is “how to create objects”, and the main characteristic is “to separate the creation and use of objects”, thus reducing the degree of business coupling, and users do not care about the details of object creation. However, not all object creation is appropriate to be handled with these creative design patterns, and we need to think about which scenarios are appropriate for which creation methods, and not abuse design patterns.

Here is talking about the creative design pattern, some non-” design pattern “things here can also talk with you, and the object, I think it can help you better understand and use the creative design pattern, you may also encounter in the work.

Creating and using objects is a critical step in a program, but using them in the wrong way can lead to disastrous changes.

If class A depends on class B, the usual way to use it is to importB in A file and instantiate class B in A. This is a fairly common way to use it, and if the business is not complex, there is no problem. Projects, but as A business of complicated, there is A lot of business object that has A complex dependencies between them, if through the way to class A directly depend on the class B keep dependencies, leads to very prone to circular references between modules, is easy to appear if the class B instantiate the parameters are changed, class B needs to be modified, The places where class A creates instances of class B need to be changed. If multiple classes depend on class B, there are A lot of places to change, which is obviously not reasonable.

Class A directly depends on class B, which itself does not follow the object-oriented “dependency inversion principle”. Factory mode solves part of the above problems to A certain extent, but factory mode is not suitable for the creation of various types of objects. When you have a large number of business objects in a project, the classes are tightly coupled, and each class will depend not only on each other but also on the dependent classes of those dependent classes, and so on, the relationships between the classes become extremely complex. And the code to create the object is all over the project, so if the constructor of the class changes, you need to change where the class is used.

My own team has encountered these problems in a project, and when a project gets complicated, it will. We need to think about how to solve this problem of business object creation and use, and we need a way to manage business objects, including object creation and acquisition. That is to say, in a way, the creation of objects and their use permissions, through a unified entry to create and reference objects, avoid direct reference between classes. The industry also has a practical solution to this problem: IoC containers.

IoC container adds a layer of container concept, meaning that the container serves as the custodian of each business object. The container is responsible for the creation of the object. If you need to use an object, take an object from the container, do not directly instantiate an object. The container is an entry point for object creation and reference. The IoC container, in essence, uses the idea of “dependency inversion”, also known as inversion of control, to solve the problem of direct reference between classes through dependency injection. Classes are decouple from each other. Unified container management solves the problem that if a constructor of a class changes, it does not need to change all parts of the class, but only needs to change in the container.

IoC container solves the problem of circular reference between modules to a certain extent in the application layer, but it cannot fundamentally solve the problem of circular reference, because the emergence of circular reference is a problem in the code design level. If the code is written with problems, it may appear the problem of circular reference between modules. Using the IoC container can only avoid the problem of circular references.

IoC container can be used to uniformly manage all objects of the project, reduce the connection between classes, further improve the reusability of the code, enhance the maintainability of the code, and improve the code organization structure of the project.

Here is not too much description of IoC container, the content is quite much, interested students can understand, is also a solution about object creation and use, front-end application is not much, back-end application is quite extensive, front-end can also borrow this idea, design in line with their own business scenarios IoC container.

The strategy pattern

From the factory model example above, you can get a sense that the code design is not very good, and even bloated, because the static crate method passes the switch… case… Or if… else… The logic of processing to create objects this way, all the business logic of the coupling in a function, if new products, continue to add new business logic in this function, this kind of behavior in logic, modify function apparently no progressive object-oriented “open closed principle”, modify the code will bring the risk of a problem, We need to avoid changing the code. Is there a way to optimize the instance code of the factory pattern to follow the “on/off principle”?

Obviously, here we talk about the strategic pattern, the strategic pattern can solve the above problems, let’s look at the strategic pattern:

define

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

The above official definition should be a bit abstract, but let’s explain it in human terms:

The core idea of the strategy mode is to find the invariable part and the changing part in the business, isolate the invariable and encapsulate the changeable. The purpose of the policy pattern is to separate the use of algorithms from the implementation of algorithms. This is the strategic pattern.

From the above definition, a code based on the policy pattern consists of at least two parts. One is the policy class, which encapsulates the specific algorithm and is responsible for the specific calculation process. The second is the Context class, which receives a request from a customer and delegates the request to a policy class for processing. The Context needs to maintain a reference to a policy object.

This means the strategy pattern program to split into two parts, the class will change the encapsulated by strategy, environment, keep the references to classes about strategy, strategy do function enhanced, thus avoiding the modify the code to realize enhancements, follow the “open closed principle”, we look at how to use the strategy pattern optimization under the instance of the factory pattern:

const ROLE = {
    USER: 'user'.ADMIN: 'admin',}/ / product
class User {
    constructor(options) {
        let { role, name, skills } = options;
        this.role = role;
        this.name = name;
        this.skills = skills;
    }
    show() {
        console.log(`The ${this.name}The user has the following functions:The ${this.skills.join(', ')}`); }}// Policy object
let userStrategy = {
    [ROLE.USER]: (options, Target) = > {
        return new Target({
           skills: ['look at'],
            ...options
        });
    },
    [ROLE.ADMIN]: (options, Target) = > {
        return new Target({
           skills: ['look at'.'new'.'delete'],... options }); }},// Abstract factory class
class AbstractSimpleUserFactory {
    constructor(options, Target) {
        throw new Error('Abstract class cannot be instantiated');
        let { role } = options;
        this.options = option;
        this.Target = Target;
        this.role = role;
    },
    // Keep references to policy objects
    [this.role]() {
        return userStrategy[this.role](options, Target); }}// Specific factory class
class SimpleUserFactory extends AbstractSimpleUserFactory {
    constructor(options, Target) {
        super(options, Target);
        let { role } = options;
        return this[role](); }}let userA = new SimpleUserFactory({role: 'user'.name: 'white'}, User);
userA.show();
let userB = new SimpleUserFactory({role: 'admin'.name: 'xiao li'}, User);
userB.show();
Copy the code

The above code is to optimize the factory method pattern with the policy pattern. The userStrategy policy object encapsulates the creation of different user objects, and extracts the creation function of user objects from the business body. They are the changing part. The body function holds the application of the policy object, and when used by SimpleUserFactory, it uses one of the algorithms in the policy object with different parameters.

Policy mode perfectly follows the “open and close principle”, encapsulates algorithms in policy classes, making them easy to switch and expand, avoiding stacking all business logic in Context and reducing the use of switch in Context… case… Or if… else… , its essence is the use of object-oriented combination and delegation characteristics, policy class through combination to encapsulate different algorithms, environment class entrust policy class to do the corresponding business logic processing.

Now that you know the strategy pattern, now you can think about the relationship between view and controller in an MVC architecture.

There are similar ideas and state patterns with the strategy pattern, but there are big differences in intent. Interested students can understand the state pattern.

Publish and subscribe model

The publish-subscribe pattern is probably the most familiar design pattern, and is too widely used to require much explanation. The publish and subscribe mode is mainly used to solve the communication problem between multiple objects. When used in actual services, objects need not exist independently. Changes in the behavior of one object may lead to changes in the behavior of one or more other objects.

For example, wechat public account, if we want to view the article of a public account, we will pay attention to the public account, when the public account released new content, will be pushed to the subscription account message, subscription account message will timely inform us of the public account has a new update, so that we can read the new content released by the public account.

In essence, the application model of public account is a publishing and subscription model, in which the public account is the publisher, the user is the subscriber, and the subscription message is the dispatch center. The user will register the subscription time of the public account with the call center. When the public account releases new content, the public account will publish the event to the dispatch center, and the dispatch center will send messages to inform the user in time.

Said to launch a subscription model, the observer pattern will have to ask, two kinds of design patterns is essentially the same, the difference is that release the subscriber mode between the publisher and subscribers in the third party, also is the control center, there is no coupling between the publisher and subscribers and publishers don’t have to care about me what are the subscriber, the subscriber also need not care about what I subscribed to the publisher, The dispatch center schedules information content uniformly. Publishers are only responsible for pushing information to the dispatch center, and subscribers only need to receive the notification from the dispatch center to obtain information, without caring who the other party is. The publish-subscribe pattern decouples objects.

However, the observer mode, without all third parties, that is, without the existence of the dispatching center, is the direct contact between the observer and the observed, which achieves the same purpose as the publish and subscribe mode, but there is the correlation between objects. Not as flexible as a publish-subscribe model.

The publish-subscribe mode has a strong application in Vue. Ve2. X’s responsivity principle and eventBus are both realized by publish-subscribe mode.

// vue/src/core/instance/events.js
export function eventsMixin (Vue: Class<Component>) {
    const hookRE = /^hook:/
    $on implements event listening
    // the event parameter is a string or string data fn performs the callback
    Vue.prototype.$on = function (event: string | Array<string>, fn: Function) :Component {
        const vm: Component = this
        // The event type is array
        if (Array.isArray(event)) {
            for (let i = 0, l = event.length; i < l; i++) {
                // Pass in the callback fn of the corresponding event event
                this.$on(event[i], fn)
            }
        } else { // The event type is a string
            If the _events object has a corresponding event value, add fn to the cache list for the corresponding event value
            // If there is no corresponding event value in the object, that is, there is no subscription, create a cache list for the event value
            (vm._events[event] || (vm._events[event] = [])).push(fn)
            // optimize hook:event cost by using a boolean flag marked at registration
            // instead of a hash lookup
            if (hookRE.test(event)) {
                vm._hasHookEvent = true}}return vm
    }
    // vm.$once the event listens once
    Vue.prototype.$once = function (event: string, fn: Function) :Component {
        const vm: Component = this
        // Bind first, delete after call
        function on () {
            vm.$off(event, on)
            fn.apply(vm, arguments)
        }
        on.fn = fn
        vm.$on(event, on)
        return vm
    }
    // vm.$off event unsubscribe
    Vue.prototype.$off = function (event? : string |Array<string>, fn? :Function) :Component {
        const vm: Component = this
        // all Clears all events
        if (!arguments.length) {
            vm._events = Object.create(null)
            return vm
        }
        // Event is an array, recursively empting the event callbacks
        // array of events
        if (Array.isArray(event)) {
            for (let i = 0, l = event.length; i < l; i++) {
                this.$off(event[i], fn)
            }
            return vm
        }

        // Event is the FN collection of the current event
        // specific event
        const cbs = vm._events[event]
        // No corresponding FN returns the VM instance
        if(! cbs) {return vm
        }
        // If no fn is passed, clear the fn set corresponding to the event value
        if(! fn) { vm._events[event] =null
            return vm
        }
        // fn traverses the corresponding FN collection, finds the same callback as the passed FN, and deletes it from the collection
        if (fn) {
            // specific handler
            let cb
            let i = cbs.length
            while (i--) {
                cb = cbs[i]
                if (cb === fn || cb.fn === fn) {
                    cbs.splice(i, 1)
                    break}}}return vm
    }
    // vm.$emit events are published
    Vue.prototype.$emit = function (event: string) :Component {
        const vm: Component = this
        if(process.env.NODE_ENV ! = ='production') {
            const lowerCaseEvent = event.toLowerCase()
            if(lowerCaseEvent ! == event && vm._events[lowerCaseEvent]) { tip(`Event "${lowerCaseEvent}" is emitted in component ` +
                `${formatComponentName(vm)} but the handler is registered for "${event}". ` +
                `Note that HTML attributes are case-insensitive and you cannot use ` +
                `v-on to listen to camelCase events when using in-DOM templates. ` +
                `You should probably use "${hyphenate(event)}" instead of "${event}". `)}}// The list of fn's in the current event
        let cbs = vm._events[event]
        if (cbs) {
            cbs = cbs.length > 1 ? toArray(cbs) : cbs
            const args = toArray(arguments.1)
            // Execute the incoming callbacks in turn
            for (let i = 0, l = cbs.length; i < l; i++) {
                try {
                    cbs[i].apply(vm, args)
                } catch (e) {
                    handleError(e, vm, `event handler for "${event}"`)}}}return vm
    }
}
Copy the code

Vue implements eventBus ($ON, $off, $OFF, $ON, $ON, $on). EventBus ($OFF, $OFF, $ON, $ON, $ON, $ON, $ON).

Publish and subscribe mode, the advantages are obvious, can do time decoupling, can do asynchronous programming. Objects can also be decoupled, using publish-subscribe mode for data communication. Let’s go back to the MVC architecture where the model and view communicate using the publish-subscribe model. It should be easier to understand now. Like vUE, which is commonly used, the implementation is based on MVVM architecture, and data changes trigger view updates. The underlying implementation is also achieved through the publish and subscribe mode. The publish and subscribe mode is a very important design mode in various architectures, and it is almost used for communication.

Summary of behavioral patterns

Both the policy pattern and the publish/subscribe pattern are classified as behavioral design patterns, which describe the complex flow control of the program at run time. Simply put, it describes how multiple classes or objects work together to accomplish tasks that a single object cannot accomplish alone. The strategy pattern is the classic application of object-oriented combination, and the template method pattern is the classic application of inheritance. Behavioral patterns In addition to the two design patterns described in this article, there are many other design patterns that you can learn to use for different business scenarios.

conclusion

This article covers only four design patterns, including two types of design patterns: creative, behavioral, and structural. You can find out for yourself. Too many design patterns, is unlikely to all design pattern to write again, I also have many design patterns are used, the purpose of writing this article is not to write an article about the design pattern of the tutorial, there are some things in contact with the pattern design, and learn something extra, do the content in the form of text output, help you comb the related content.

Learning this relatively theoretical content will have a more obvious learning effect in the actual business. Think more about what is the driving force behind the emergence of this technology, why this technology appears, what problems it can solve, and whether there are other shortcomings. For example, the essence of design pattern is object-oriented, what is the essence of object-oriented, three characteristics and five basic principles, understand these contents, the mystery of design pattern is gone. Pure theoretical learning, may be to see mountains are mountains, see water is water.

This is the end of the design pattern, and there are a lot of content I am further learning, more accumulation, more practice.