In depth understanding of the JavaScript series (39) : adapter pattern details for design patterns

  • 2020-05-10 17:38:30
  • OfStack

introduce

The adapter pattern (Adapter) converts the interface (method or property) of a class (object) into another interface (method or property) that the client wants. The adapter pattern allows classes (objects) that would otherwise not work because of incompatible interfaces to do so. Crash packager (wrapper).

The body of the

For example, ducks (Dock) fly (fly) and quack (quack), while turkeys fly (fly) but cackle (gobble). If you really want a Turkey to quack (quack), we can reuse the quack method of the duck, but the specific quack should also be a cackle. At this point, we can create a Turkey adapter so that the Turkey can support the quack method, which still calls gobble internally.

OK, let's start with the step by step implementation. First, we need to define the abstract behavior of ducks and turkeys, namely their method functions:


// The duck
var Duck = function(){ };
Duck.prototype.fly = function(){
throw new Error(" The method must be overridden !");
};
Duck.prototype.quack = function(){
throw new Error(" The method must be overridden !");
} // The Turkey
var Turkey = function(){ };
Turkey.prototype.fly = function(){
    throw new Error(" The method must be overridden !");
};
Turkey.prototype.gobble = function(){
    throw new Error(" The method must be overridden !");
};

Then define the specific constructors of duck and Turkey as follows:

// The duck
var MallardDuck = function () {
    Duck.apply(this);
};
MallardDuck.prototype = new Duck(); // The prototype is Duck
MallardDuck.prototype.fly = function () {
    console.log(" Can fly for a long distance !");
};
MallardDuck.prototype.quack = function () {
    console.log(" Ga ga! Ga ga! ");
}; // The Turkey
var WildTurkey = function () {
    Turkey.apply(this);
};
WildTurkey.prototype = new Turkey(); // The prototype is Turkey
WildTurkey.prototype.fly = function () {
    console.log(" The flying distance seems a little short !");
};
WildTurkey.prototype.gobble = function () {
    console.log(" Giggle! Giggle! ");
};

To get the Turkey to support the quack method, we created a new Turkey adapter, TurkeyAdapter:

var TurkeyAdapter = function(oTurkey){
    Duck.apply(this);
    this.oTurkey = oTurkey;
};
TurkeyAdapter.prototype = new Duck();
TurkeyAdapter.prototype.quack = function(){
    this.oTurkey.gobble();
};
TurkeyAdapter.prototype.fly = function(){
    var nFly = 0;
    var nLenFly = 5;
    for(; nFly < nLenFly;){
        this.oTurkey.fly();
        nFly = nFly + 1;
    }
};

This constructor takes an instance object of a Turkey, apply using Duck, whose adapter prototype is Duck, and then rewrites the quack method of its prototype to internally call the oTurkey.gobble () method. The fly method has also been changed to let the Turkey fly five times in a row (internally calling its own oTurkey.fly () method).

Call the method, it is clear, test 1 can know the result:


var oMallardDuck = new MallardDuck();
var oWildTurkey = new WildTurkey();
var oTurkeyAdapter = new TurkeyAdapter(oWildTurkey); // Original duck behavior
oMallardDuck.fly();
oMallardDuck.quack(); // Original Turkey behavior
oWildTurkey.fly();
oWildTurkey.gobble(); // Adapter Turkey behavior (method name for Turkey calling duck)
oTurkeyAdapter.fly();
oTurkeyAdapter.quack();

conclusion

What about the appropriate use of the adapter pattern? It is recommended to use when:

1. Use an existing object whose method or property interface does not meet your requirements;
2. You want to create a reusable object that works with other unrelated or invisible objects (that is, objects with incompatible interface methods or properties);
3. You want to use an existing object, but you can't prototype each one to match its interface. An object adapter can adapt its parent object interface methods or properties.

In addition, the adapter pattern and several other patterns can be confusing. Here are some general differences:

1. Although the adapter and the bridge pattern are similar, the starting point of the bridge is different. The purpose of the bridge is to separate the interface part from the implementation part, so that they can be changed more easily and relatively independently. An adapter means changing the interface of an existing object.
2. The decorator pattern enhances the functionality of other objects without changing their interfaces, so it is more transparent to the corresponding program than the adapter. The result is that the decorator supports recursive composition, while purely using the adapter is not possible.
3. The proxy pattern defines a proxy for another object without changing its interface.


Related articles: