Those design patterns that you inadvertently use (1)-creational patterns

Those design patterns that you inadvertently use (1)-creational patterns

Preface

A few days ago, I shared a few less rigorous mind maps, including one about design patterns:

For a long period of time, I could only remember certain design patterns, and they did not apply well.

Simply use this picture as an outline to talk about the design patterns that we inadvertently use --- creation.

1. 3.factory modes: FactoryPattern

Generally speaking, the three design patterns are:

  • Simple factory pattern ( SimpleFactory)
  • Factory method pattern ( Factorymethod)
  • Abstract factory pattern ( Abstractfactory)

The core is:

The role of the factory is to hide the complexity of creating an instance, only need to provide an interface, simple and clear. --- Excerpted from "The Way of Front-end Interview"

The difference is:

  • Simple factory pattern, used to create an instance of a certain product object, used to create a single object.
  • The factory method pattern defers the creation of the instance to the subclass.
  • The abstract factory pattern is an abstraction of a class factory to create a product class cluster, and is not responsible for creating an instance of a certain type of product.

In fact, you will use from jQuerythe beginning, has been using the factory pattern:

JavaScript design pattern and practice--factory pattern

1. jQueryof$(selector)

jQueryIn $('div')and new$('div')which easy to use? It is clear that direct $()most convenient, because it is $()already a factory way to go.

class jQuery {
    constructor(selector) {
        super(selector)
    }
   //....
}

window.$ = function(selector) {
    return new jQuery(selector)
}

2. ReactofcreateElement()

React.createElement()Method is a factory method

React.createElement('h1', null,'Hello World!'),

3. VueAsynchronous components

By promiseway resolveout of a component

Corresponding source code:

export function createComponent (
  Ctor: Class<Component> | Function | Object | void,
  data: ?VNodeData,
  context: Component,
  children: ?Array<VNode>,
  tag?: string
): VNode | Array<VNode> | void {
   //... logic processing
   //async component
    let asyncFactory
    const vnode = new VNode(
    `vue-component-${Ctor.cid}${name? `-${name}`:''}`,
    data, undefined, undefined, undefined, context,
    {Ctor, propsData, listeners, tag, children },
    asyncFactory
    )
}

2. Singleton mode: SingletonPattern

The singleton pattern is one of the simplest design patterns. To explain in a big vernacular is:

Available everywhere after one instance

There are three main points of the singleton pattern:

  • There can only be one instance of a class;
  • It must create this instance by itself;
  • It must provide this instance to the entire system on its own.

From a specific implementation perspective, it is the following three points:

  • Classes in singleton mode only provide private constructors
  • The class definition contains a static private object of the class
  • This class provides a static public function for creating or obtaining its own static private object.

Similarly, it is also one of the first design patterns we came into contact with:

1. Reference third-party libraries

Repeatedly quoted only use a library reference, such as jQuery, lodash, momentand so on.

2. Vuex/Redux

Global state management store

VuexAnd Reduxdata stored in a single storemedium, Mobxthe data stored in the plurality of dispersion storein

const store = createStore(reducer)

render(
  <Provider store={store}>
    <App/>
  </Provider>,
  document.getElementById('root')
)

3. Installation Vueof third-party plug-ins

The first is the Vuexinstallation:

let Vue//bind on install

export function install (_Vue) {
  if (Vue && _Vue === Vue) {
   //If Vue is found to have a value, the instance will not be recreated
    return
  }
  Vue = _Vue
  applyMixin(Vue)
}

Other similar, interested can go GitHubsearchexportfunctioninstall(Vue)

4. Simple implementation of a singleton pattern:

class SingletonClass {
  constructor() {
    if (!SingletonClass.instance) {
      SingletonClass.instance = this;
    }

    return SingletonClass.instance;
  }
 //other things
}

const instance = new SingletonClass();
Object.freeze(instance);

export default instance;

3. Builder mode: BuilderPattern

, Builder mode is mainly used to "build a complex object in steps"

This "step by step" is a stable algorithm, and the various parts of a complex object often change.

In a word: the commander assigns tasks, the builder develops, and each fulfills its responsibilities, and stabilizes in a large process.

An Interpretation of the Conceptual Imitation of the Builder Mode

If a lady wants to build a villa, she needs to find a contractor, and the contractor will assign specific tasks to the workers, and then give it to the lady to use.

1. jQueryThe builder in

jQueryThe middle builder mode is reflected in:

$( "<div class= "foo">bar</div>" );

$( "<p id="test">foo <em>bar</em></p>").appendTo("body" );

var newParagraph = $( "<p/>" ).text( "Hello world" );

$( "<input/>")
      .attr({ "type": "text", "id":"sample"});
      .appendTo("#container");

The following is jQueryan internal source jQuery.prototypea segment method, it is transmitted to the jQuery()build tag selector jQueryobjects.

Whether document.createElementused to create new elements, the elements (find or create) a reference will be injected into the returned object, so .attr()you can use other methods immediately thereafter.

//HANDLE: $(html) -> $(array)
    if (match[1]) {
      context = context instanceof jQuery? context[0]: context;
      doc = (context? context.ownerDocument || context: document );

     //If the incoming string is a single string, and it is a single tag
     //Just execute createElement and skip the rest

      ret = rsingleTag.exec( selector );

      if (ret) {
        if (jQuery.isPlainObject( context)) {
          selector = [document.createElement( ret[1]) ];
          jQuery.fn.attr.call( selector, context, true );

        } else {
          selector = [doc.createElement( ret[1]) ];
        }

      } else {
        ret = jQuery.buildFragment( [match[1] ], [doc] );
        selector = (ret.cacheable? jQuery.clone(ret.fragment) 
        : ret.fragment ).childNodes;
      }

      return jQuery.merge( this, selector );

1. The ideal realization of the builder model

Essentially, the goal of the builder pattern is to reduce the number of parameters used by the constructor and provide a way to add flexible behavior to the object.

//Before using the builder mode
const person1 = new Person('Peter', 26, true, 40074986, 4, 2);

//After using the builder mode
const person1 = new Person();
person1
  .name('Peter')
  .age(26)
  .member(true)
  .phone(40074986)
  .children(4)
  .cars(2);

2. ES6The builder mode in

Let's assume a business scenario of a commodity entry system. There are four required information: name, price, and category. The buildmethod returns the final JavaScriptobject.

//Book builder class
class ProductBuilder {
  constructor() {
    this.name ='';
    this.price = 0;
    this.category ='';
  }

  withName(name) {
    this.name = name
    return this
  }

  withPrice(price) {
    this.price = price
    return this
  }

  withCategory(category) {
    this.category = category
    return this
  }

  build() {
    return {
      name: this.name,
      price: this.price,
      category: this.category,
    }
  }
}

console.log(
  new ProductBuilder()
    .withName('"Harry Potter"')
    .withCategory('book')
    .withPrice('29.9')
    .build()

Although there are only three properties, our builder is already quite large and requires a lot withers.

The size of the builder grows linearly with the number of fields. We have too many withxxxxmethods. In fact, we can automatically create this type of withxxxxmethod to simplify the code.

3. Simplified builder mode

class ProductBuilder {
  constructor() {
    this.name =''
    this.price =''
    this.category ='other'

   //Generate `wither` for each attribute
    Object.keys(this).forEach(key => {
      const witherName = `with${key.substring(0, 1).toUpperCase()}${key.substring(1)}`
      this[witherName] = value => {
        this[key] = value
        return this
      }
    })
  }

  build() {
   //Get an array of all non-function attributes of this generator
    const keysNoWithers = Object.keys(this).filter(key => typeof this[key] !=='function')

    return keysNoWithers.reduce((returnValue, key) => {
      return {
        ...returnValue,
        [key]: this[key],
      }
    }, {})
  }
}

console.log(
  new ProductBuilder()
    .withName('"Harry Potter"')
    .withCategory('book')
    .build()
)

We will automatically create all the construction methods withxxxx when the constructor is called. Here we use some new ES6 syntax: Object.keys gets the object attribute array, the syntax of the merged object...

In the end we got a declarative (easy to understand) method, and a builder pattern that can dynamically add attributes.

5. Extract common parts to realize multiple builders

When you have many builders, we can easily extract the generalized part into a common parent class, so that new builders can be created very easily.

class BaseBuilder {
  init() {
    Object.keys(this).forEach((key) => {
      const witherName = `with${key.substring(0,1).toUpperCase()}${key.substring(1)}`;
      this[witherName] = (value) => {
        this[key] = value;
        return this;
      };
    });
  }

  build() {
    const keysNoWithers = Object.keys(this).filter((key) => (
      typeof this[key] !=='function'
    ));

    return keysNoWithers.reduce((returnValue, key) => {
      return {
        ...returnValue,
        [key]: this[key]
      };
    }, {});
  }
}

Then you can create multiple builders:

class ProductBuilder extends BaseBuilder {
  constructor() {
    super();

    this.name ='"The Secret of Front-end Persuading Retirement"';
    this.price = 9.99;
    this.category ='other';

    super.init();
  }
}

It can be seen that the use of builder mode is only suitable for creating extremely complex objects. In the actual front-end business, when there is no such extremely complex object creation, you should still directly use the object literal or factory pattern to create the object.

4. Prototype Mode

prototype...More about being hacked to death.

5. Next article: Structural design mode

Originally, I planned to slap it with more than 10,000 words and write all the design patterns all over.

But think, this reading experience is actually not good (mainly lazy, I want to write slowly.)

Oh, right now, there are still reliable people who can contact me

  • WeChat: huab119
  • mailbox: 454274033@qq.com

Reference article

  • An Exploration of JavaScript Builders
  • The Builder Pattern
  • "The Way of Front-end Interview"

Author Nuggets Article Collection

If you need to repost it to the official account, just call me to add the whitelist.

  • "True┬« Full Stack Road" Back-end guide for web front-end development
  • "Vue Practice" A Vue CLI plug-in in 5 minutes
  • "Vue practice" arm your front-end project
  • "Intermediate and advanced front-end interview" JavaScript handwritten code invincible cheats
  • ``Learn from the source code'' Vue question answers that interviewers don't know
  • "Learn from the source code" JS Sao operation in Vue source code
  • "Learn from the source code" thoroughly understand the Vue option Props
  • The correct posture of the "Vue practice" project to upgrade vue-cli3
  • Why can't you understand the JavaScript scope chain?
Reference: https://cloud.tencent.com/developer/article/1488442 Those design patterns you inadvertently use (1)-Creational Pattern-Cloud + Community-Tencent Cloud