The code has been written for several years, and the design pattern is in a state of forgetting and forgetting. Recently, I have some feelings about the design pattern, so I will learn and summarize it again.

Most speak design pattern articles are using Java, c + + such based on the class the static type of language, as a front-end developer, js this prototype based dynamic language, function has become a first class citizen, slightly different on some design patterns, even simple to don’t like to use the design patterns, sometimes also can produce some confusion.

The following are summarized in the order of “scenario” – “Design Pattern definition” – “code implementation” – “more scenarios” – “total”. If there are any improper points, welcome to discuss.

scenario

When we use a third-party library, we often encounter a mismatch between the current interface and the third-party interface. For example, using a Table component, it requires us to return the Table data format as follows:

{
  code: 0./ / business code
  msg: ' '.// Error prompt
  data: {
     total:,/ / the total number
     list: [], // Table list}};Copy the code

But the data returned from the back end might look something like this:

{
  code: 0./ / business code
  message: ' '.// Error prompt
  data: {
     total:,/ / the total number
     records: [], // Table list}};Copy the code

At this point, you can transform through the adapter pattern.

Adapter mode

Take a look at wikipedia’s definition:

In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface.[1] It is often used to make existing classes work with others without modifying their source code.

The adapter pattern allows you to use another class without changing the current one.

There are two implementations in class-based languages, one by composition, where the adapter class contains an instance of the original object inside. One is through class inheritance, where the adapter class inherits the original class. Take a look at the UML class diagram:

The Adapter on the left has an instance of Adaptee inside, and the Adapter class on the right inherits the Adaptee class directly.

The adapter wraps Adaptee’s specificOperation methods as operation methods for client use.

Take a simple example. In real life, iPhone has two kinds of headphone jack, one is Lightning and the other is traditional 3.5mm port. If lightning headphones want to plug into a traditional 3.5mm PC, you’ll need an adapter.

class lightningThe headset{
	public voidInsert Lighting interface (){system.out.println ()"Plug into Lighting headphone jack successfully."); }}classTraditional headphones{
	public voidInsert into traditional headphone jack (){system.out.println ()"Inserted into traditional headphone jack successfully."); }}class lightningHeadset to traditional headset adapterextendsTraditional headphones{public Lightning headset Lightning headset; Public Lightning headset to traditional headset adapter (Lightning headset headset) {Lightning headset = headset; } publicvoidPlug into traditional headphone jack (){Lightning headphone. Insert Lighting interface (); }}classComputer traditional headphone jackPublic traditional earphone earphone; Public PC traditional headphone jack (traditional headphone traditional headphone) {headset = traditional headphone; } publicvoidInsert earphone () {earphone. Insert into traditional headphone jack (); } } publicclass Main {
	public static void main(String[] args){traditional headphones Traditional headphones =newTraditional earphone (); Computer traditional headphone jack computer traditional headphone jack =newPC traditional headphone jack (traditional headphone); Computer traditional headphone jack. Insert headphones ();// Successfully inserted into the traditional headphone jackLightning Headphones Lightning headphones =newFrom the headset (); Computer traditional headphone jack Computer traditional headphone jack2 = newComputer Traditional Headphone jack (newLightning Headset to Traditional Headset Adapter (Lightning Headset)); Computer traditional headphone jack2.Insert headphones ();// Plug into the Lighting headphone jack successfully}}Copy the code

Through the adapter, we successfully inserted the Lightning earphone into the traditional headphone hole of the computer. Let’s rewrite it with JS.

constLightning earphone = {insert Lightning port (){console.log("Plug into Lighting headphone jack successfully."); }}constTraditional headphone = {Insert into traditional headphone jack (){console.log("Inserted into traditional headphone jack successfully."); }}constComputer traditional headphone jack = {Insert earphone (earphone) {earphone. Insert into traditional headphone jack (); }}constLightning headset to traditional headset adapter =function(From the headset) {
    return{Plug into the traditional headphone jack (){Lightning headphone. Plug into Lighting port ()}}} PC traditional headphone jack. Plug in headphones (traditional headphones)// Successfully inserted into the traditional headphone jackComputer traditional headphone jack. Plug in headphones (Lightning Headphones to traditional Headphone adapters (Lightning Headphones))// Plug into the Lighting headphone jack successfully
Copy the code

Code implementation

Returning to the initial interface mismatch, the Table component provides a responseProcessor hook that wraps the data returned by the interface.

{...responseProcessor(res) {
    return {
      ...res,
      msg: res.message, // Error prompt
      data: {
         ...res.data
         list: res? .data? .records || [],// Table list}}; },... }Copy the code

More scenes

In addition to dealing with inconsistent data formats, the adapter pattern provides a unified interface for the upper layer to address compatibility issues. The best example of this is jQuery, where you can take a look:

// Create the request object
// (This is still attached to ajaxSettings for backward compatibility)
jQuery.ajaxSettings.xhr = window.ActiveXObject ! = =undefined ?

	// Support: IE6-IE8
	function() {

		// XHR cannot access local files, always use ActiveX for that case
		if ( this.isLocal ) {
			return createActiveXHR();
		}

		// Support: IE 9-11
		// IE seems to error on cross-domain PATCH requests when ActiveX XHR
		// is used. In IE 9+ always use the native XHR.
		// Note: this condition won't catch Edge as it doesn't define
		// document.documentMode but it also doesn't support ActiveX so it won't
		// reach this code.
		if ( document.documentMode > 8 ) {
			return createStandardXHR();
		}

		// Support: IE<9
		// oldIE XHR does not support non-RFC2616 methods (#13240)
		// See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
		// and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
		// Although this check for six methods instead of eight
		// since IE also does not support "trace" and "connect"
		return /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
			createStandardXHR() || createActiveXHR();
	} :

	// For all other browsers, use the standard XMLHttpRequest object
	createStandardXHR;
Copy the code

Mixable design patterns

The adapter pattern is similar in code structure to the proxy pattern, which also wraps the original object. The difference lies in their intent:

  • The adapter pattern is used to solve the problem of a mismatch between two objects where the original object is not suitable for direct modification and can be used for a layer of transformation.

  • The proxy mode is designed to enhance the functionality of the original object, and the interface provided does not change.

The total

Adapter pattern is a relatively simple design pattern, in JS will be very natural application, generally through a function to transform.

More design patterns recommended reading:

Front end design mode series – strategic mode

Front-end design mode series – proxy mode

Front end design mode series – decorator mode

Front end design mode series – Observer mode

Front end design pattern series – publish subscribe pattern