Design Patterns: Adapter and Facade Pattern

These notes were adapted from various readings detailed in the References section.


Adapter Pattern

The Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

Suppose you have an existing software system that you need to work a new class library into. However, this new class has a different interface than all other classes in your system. You do not want to solve the problem by changing your existing code to just fit this one scenario.

We attempt to try and wrap objects to make their interfaces look like something they are not. What we can do is try to write a new class that adapts the new class interface into the one which we should be expecting.

Think of it as this: The class which you create to adapt into an incompatible interface is called the adapter. The adapter acts as the middleman by receiving requests from the client, and converting them into requests that make sense for the receiving incompatible class.

Let’s revisit the duck example. What if we wanted to make a Turkey disguised as a Duck? Let’s actually write an adapter for it!

interface Duck {
    quack();
    fly();
}

class MallardDuck implements Duck {
    public quack() {
        log("Quack");
    }
    
    public fly() {
        log("I'm flying...");
    }
}

interface Turkey {
    gobble();
    fly();
}

class WildTurkey implements Turkey {
    public gobble() {
        log("Gobble gobble");
    }
    
    public fly() {
        log("I'm flying a short distance...");
    }
}

Now, we want to bring the WildTurkey into the Duck world. How would we do that? We can write a TurkeyAdapter which implements the Duck interface to solve this!

class TurkeyAdapter implements Duck {
    private turkey;
    
    public constructor(turkey) {
        this.turkey = turkey;
    }
    
    public quack() {
        this.turkey.gobble();
    }
    
    public fly() {
        this.turkey.fly();
    }
}

Now, because of the existence of this adapter, a Turkey can be invoked as if it was a Duck. This results in making the Turkey compatible in the world of Ducks.

If you have a large class you need to adapt, you can simply just define an interface with only the base set of methods you would like to adapt, and have the adapter just implement those base set of interface methods to get your class compatible.

Facade Pattern

The Facade Pattern provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

The Facade pattern allows an interface which simplifies another interface. By definition “facade” means to hide. We can think of it as a pattern that “hides” the complexity of one or more classes behind a cleaner implementation.

The Facade object is also free to add any additional logic to make the system easier to use overall.

What is the difference between an Adapter and a Facade? The Adapter is an object to serve as an intermediary to another interface a client is expecting. The Facade provides a simplified interface to the system which the client can directly call.

References

  • Head First Design Patterns - Eric Freeman & Elisabeth Freeman - https://www.oreilly.com/library/view/head-first-design/0596007124/