Adapter Pattern

Francesco Ciulla - Mar 17 '20 - - Dev Community

Structural Design Pattern

Github link: https://github.com/FrancescoXX/Design-Pattern-Adapter-Javascript


đź“ŚIntroduction

The Adapter pattern is used to allow a new use of an existing interface of a class, with a new interface, using the same methods.
We separate the code well (Single responsibility principle).
We dont need to change the existing class (open/closed principle).


⚡️In short

We have:
Target: Interface the client uses.
Adapter: Transforms the request of the client to a specific request.
Adapteee: Class we want to adapt.


đź’ˇIntent

  • Wrap an existing class with a new interface.
  • Convert an interface into another one.
  • Let classes work together that couldn't otherwise because of incompatible interfaces.

🔧 Apply when (we want to)

  • Re-use an existing class, but the interface is not compatible
  • Combine unrelated classes with an incompatible interface

âś…Pro

  • Single Responsibility Principle: We can separate the different interfaces' logic.
  • Open/Closed Principle. We can introduce new adapters without breaking the existing code.

⚠️Cons

  • How much adapting does the adapter do? Complex adaptations could be be hard to write
  • The overall complexity of the code increases
  • We need to introduce new interfaces and classes.
  • Sometimes it’s better to change the class. (Not always possible by the way).

🏆 Great for

  • Connect to legacy systems
  • Adapt one interface to another

/** Adapter Design pattern
 *  
 *  Structural Design Pattern
 */

//Target
class LegacyShopper {
  constructor() {
    this.request = (product, quantity, price) => `${price * quantity}$`;
  }
}

// Adapteee
class OnlineShopping {
  constructor() {
    this.authenticate = (username, password) => console.log(`login logic for...${username} // ${password}`);
    this.setProduct = (product) => console.log(`setting product to ${product}`);
    this.setQuantity = (quantity) => console.log(`setting quantity to ${quantity}`);
    this.applyDiscount = (price) => price * 0.9; // online discount
    this.checkout = (quantity, price) => `${(this.applyDiscount(price)) * quantity}$`;
  }
}

// Adapter interface
class Adapter {
  constructor(username, password) {
    const cart = new OnlineShopping();
    cart.authenticate(username, password);

    this.request = (product, quantity, price) => {
      cart.setProduct(product);
      cart.setQuantity(quantity);
      return cart.checkout(quantity, price);
    }
  };
}

// legacy shopping
const cart = new LegacyShopper();
console.log("***Legacy system***");
console.log("Standard cost: " + cart.request("apples", 10, 3));

// OUTPUT
//
//***Legacy system***
//Standard cost: 30$

//////////////////////////////////////////////////////////////

// new shopping with Adapted interface
console.log("\n***New system***");

const adapter = new Adapter("Francesco", "123456"); //login logic simulation
//Same request, using the adapter
console.log("Online cost: " + adapter.request("apples", 10, 3)); //27$

// OUTPUT:
//
// ***New system***
// login logic for...Francesco // 123456
// setting product to apples
// setting quantity to 10
// Online cost: 27$
Enter fullscreen mode Exit fullscreen mode

Github link: https://github.com/FrancescoXX/Design-Pattern-Adapter-Javascript

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .