preface

Mention of design pattern may feel a little lofty feeling, in fact, the concept of this thing is very abstract, but in the actual development, there are still many places to use the idea of design pattern, to optimize our code. The purpose of this article is to introduce some common design patterns used in development, learn from examples, and try to skim through the concepts. For the sake of the adoration of the little sister next door front end, learn together!

The body of the

1. Adapter pattern

Concept: To convert the interface of one class to another to meet the user’s needs, so that incompatibilities between interfaces between classes (objects) can be resolved through adapters.

At work, there are times when a new module needs to be compatible with an old module in order to meet the requirements. This is when the adapter pattern is needed.

Such as:

  1. Method passes parameters by default
Function doSomething (obj){const Adapter = {name:" default name ", color:"red", size:200, age:20 } for (let i in adapter){ adapter[i] = obj[i] || adapter[i]; } // do some thing }

And you can see that when we do that we’re guaranteed to have these properties in the object regardless of what argument we pass in. Avoid subsequent logic errors.

  1. Extensions and compatibility of global encapsulation methods.

In Vue usage, API requests are usually mounted on Vue instances, but some older projects are done by encapsulating Ajax requests, and refactoring old projects requires placing all API requests on Axios or Fetch. This allows the adapter pattern to be used.

Export default class FetchApi{static get(url){return new Promise((resolve,reject)=>{return new Promise((resolve,reject))=>{return new Promise((resolve,reject))=>{ fetch(url).then(...) .catch(err=>reject(err)) }) } static post(url,data){ return new Promise(...) }} / / when we use so we use the const res = await FetchApi. Get (url) | | {}; / / or const res = await FetchApi. Post (url, params) | | {} / / look at the original way of interface encapsulation Pseudo code function Ajax (type, url, data) {const XHR = new XMLHttpRequest() ... if(type === 'GET'){ xhr.open('GET',url+"?" +data,true); xhr.send() }else if(type === 'POST'){ xhr.open('POST',url,true); xhr.setRequestHeader("Content-type",'application/x-www-form-urlencoded') xhr.send(data) } ... } // call Ajax("GET",url,data)

Here we can see that the interface names of the old and new interfaces are different, and the request arguments are different. Never mind, use the adapter.

/ / pseudo-code async function ajaxAdapterr (type, url, data) {let result if (type = = = 'GET') {result = await FetchApi. GET (url) | | {}  }else if(type === 'POST'){ result = await FetchApi.post(url,data) || {} } } async function Ajax(type,url,data){ await ajaxAdapterr(type,url,data); }

This allows the original AJAX request to be changed to the FETCH, avoiding the need to modify the request in the page one by one. It saves a lot of time to fish.

2. Strategic patterns

Concept: To encapsulate a defined set of algorithms so that they are interchangeable with each other. The encapsulated algorithm is independent and will not change with the change of the client.

Concepts are good at describing what everyone knows and adults don’t know. Let’s look at the actual scene.

In your work, I’m sure you’ve written a lot of if else judgments. As more and more conditions become available, this style of writing can become very cumbersome, so use the strategy mode to optimize.

Such as:

function doSomeThing(type){ if(type === 'pre'){ return 100 }else if(type === 'onSale'){ return 200 }else if(type === 'back'){return 150}else if(type === 'fresh'){return 250}} // function doSomething (type){const priceType = { pre(){ return 100 }, onSale(){ return 200 }, back(){ return 150 }, fresh(){ return 250 } } return priceType[type]() }

As you can see, after using the policy pattern optimization, the mapping relationship of the code is very clear, and more flexible and intuitive, and the later maintenance only needs to add methods to the object. Handsome on a word, I only say once. This code which front sister did not see the good?

3. State patterns

Concept: When an object’s internal state is changed, it causes a change in its behavior, which looks like changing the object.

The concept of a state pattern is similar to that of a policy pattern in that both encapsulate behavior and distribute behavior through delegation. But the methods distributed in the strategy model are not dependent, they are parallel to each other, and the water does not invade the river. In the state mode, there is a certain correlation between the functions and the subject.

Such as:

Automatic coffee machine

Class Coffee{constructor(){this.state =' constructor '; } stateProcessor = {American: () = > {the console. The log (" black coffee ")}, places: () = > {this. StateProcessor. American (); / / to make black coffee console. The log (" white ")}, vanillaLatte: () = > {this. StateProcessor. Places (); The console. The log (" add vanilla 🌿 syrup ")}, mocha: () = > {this. StateProcessor. Places (); Console. log(' Add chocolate 🍫')}} changeState(state){this.state = state; if(! This. stateProcessor[state]){return console.log(" StateProcessor [state] ")} this.stateProcessor[state]()} const coffee = new coffee ();  coffee.changeState("latte")

The state mode mainly solves the situation when the conditional expression controlling the state of an object is too complicated. By transferring the judgment logic of the state to a series of classes representing different states, the complicated judgment logic can be simplified.

4. Proxy mode

Concept: Since one object cannot directly reference another object, you need to mediate between the two objects through a proxy object.

Proxies may be involved in common development, the basic kind of proxy is not introduced here, here to introduce the cache proxy

For example, summing an incoming parameter

Const addAll = function() {console.log(' A new calculation took place ') let result = 0 const Len = arguments.length for(let i = 0; i < len; I ++) {result += arguments[I]} return result} // create proxy const proxyAddAll = (function(){// create pool const for the result of summations ResultCache = {} return function () {/ / convert into the reference to a unique into the parameter string const args = Array. The prototype. Join. The call (the arguments, If (resultCache) {if(resultCache) {if(resultCache) {if(resultCache) { Return resultCache[args]} return resultCache[args] = addAll(... arguments) } })()

As you can see, in the case of consistent input parameters, only one calculation is done, and the subsequent values are returned from the cache, which can save a lot of time in the case of excessive computation.

5. Decorator

Concept: By wrapping and extending the original object (adding properties or methods) without changing the original object, the original object can meet more complex requirements.

For example, in the approval flow, the original demand is that the approval and rejection are all processed together, and the later demand is added, and a pop-up box should be displayed to input the reason for rejection when the rejection is made

// do some thing} function rejectShowBox(){this.approvalOrReject(); this.showMessageBox(); // display popup}

In this way, we have implemented the “add, don’t modify” decorator pattern. The Decorator pattern in real development is very useful, and you can find it by heart

summary

For now, let’s summarize these design patterns, and we will continue to add them in the future. Please pay attention to them

Since using the design mode, little sister began to nod to me, brothers, use it.

Due to my limited ability, please feel free to contact me if there is any error in this article.