Skip to main content

Facade Pattern

Free2015-03-07#Design_Pattern#外观模式#Facade Pattern

The Facade Pattern provides a simple, easy-to-use high-level interface for complex subsystems. If you find that implementing a simple feature requires calling many low-level components of a subsystem, then you may need the Facade Pattern to save you.

no_mkd

I. What is the Facade Pattern?

Simply put, the Facade Pattern is used to simplify interfaces.

Often, we find a subsystem difficult to use because its external interface is too close to the low-level components, making it troublesome for us.

We don't need to know the internal details; we just want a "one-click completion" feature. Call a method of the subsystem, and it may complete image preprocessing for us, rather than relying on ourselves to call grayscale methods, image enhancement algorithms, noise processing methods, etc., step by step to achieve preprocessing.

If the interface provided by the subsystem is too close to low-level components, it is not only inconvenient but also breaks the encapsulation of the subsystem (to call the subsystem, we must understand each of its low-level components; we are forced to know too many details we shouldn't know...)

II. An Example

Suppose there is a well-encapsulated old-fashioned washing machine that provides these external interfaces:

package FacadePattern;

/**

  • @author ayqy

  • Define washing machine interface / public interface Washer { /

    • Common part
    • */ // Connect to power public abstract boolean connectToPower();

    /*

    • Washing part
    • */ // Open the left washing compartment public abstract void openLeftSide(); // Open the water inlet public abstract void openWaterHole(); // Start water injection public abstract void startWaterInjection(); // Stop water injection public abstract void stopWaterInjection(); // Start rotating the left washing compartment public abstract void startWashing(); // Stop rotating the left washing compartment public abstract void stopWashing();

    /*

    • Dewatering part
    • */ // Open the right dewatering compartment public abstract void openRightSide(); // Start rotating the right dewatering compartment public abstract void startDewatering(); // Stop rotating the right dewatering compartment public abstract void stopDewatering();

    /*

    • Drainage part omitted...
    • */ }

Unfortunately, it is too old to meet our modern life needs, but we can't afford a new automatic washing machine, so we need to turn it into a semi-automatic washing machine, using the time saved to write code... First, let's see how we use the old washing machine to wash clothes:

package FacadePattern;

/**

  • @author ayqy

  • Using the old washing machine to wash clothes */ public class Washing implements Washer{

    public static void main(String[] args) { // Create washing machine object Washer washer = new Washing(); // Connect to power if(washer.connectToPower()){ // Open washing compartment washer.openLeftSide(); /* Loading dirty clothes omitted / // Open water inlet washer.openWaterHole(); // Start water injection washer.startWaterInjection(); / Wait 5 minutes / // Stop water injection washer.stopWaterInjection(); / Adding detergent omitted / // Start washing washer.startWashing(); / Stop after 15 minutes */ washer.stopWashing();

     	/*
     	 * Dewatering part omitted
     	 * */
     }
    

    }

    /*

    • Ignore all these auto-generated things below...
    • */ @Override public boolean connectToPower() { // TODO Auto-generated method stub return false; }

    @Override public void openLeftSide() { // TODO Auto-generated method stub

    }

    @Override public void openWaterHole() { // TODO Auto-generated method stub

    }

    @Override public void startWaterInjection() { // TODO Auto-generated method stub

    }

    @Override public void stopWaterInjection() { // TODO Auto-generated method stub

    }

    @Override public void startWashing() { // TODO Auto-generated method stub

    }

    @Override public void stopWashing() { // TODO Auto-generated method stub

    }

    @Override public void openRightSide() { // TODO Auto-generated method stub

    }

    @Override public void startDewatering() { // TODO Auto-generated method stub

    }

    @Override public void stopDewatering() { // TODO Auto-generated method stub

    } }

Just demonstrating the process of washing clothes, we called so many operations, and we must know the internal details of this washing machine; otherwise, we cannot use it at all... Washing clothes may take 60 minutes (water injection + washing + dewatering + drainage). During this time, we can hardly do anything else; we can only squat beside the washing machine, constantly operating the machine.

I think we may need a remote control with 2 buttons:

  • Wash
  • Dewater

Then our washing process will become:

  1. Press the wash button: automatically connect to power, automatically open the washing compartment, automatically inject water for 5 minutes, automatically start washing for 15 minutes
  2. Press the dewater button: automatically open the dewatering compartment, automatically dewater for 10 minutes, automatically drain, automatically disconnect power

This is absolutely fantastic. We can press the wash button before lunch, go put the clothes on the right side after eating, press the dewater button, then go to work. Come back in the afternoon and hang the clothes to dry (of course, manually moving clothes from left to right is unavoidable; after all, it is too old; turning it into a fully automatic washing machine is impossible...)

Let's look at the remote control we made ourselves:

package FacadePattern;

/**

  • @author ayqy

  • Remote control (also known as the Facade) */ public class WasherFacade { private Washer washer;

    public WasherFacade(Washer washer){ this.washer = washer; }

    /**

    • Automatic washing / public void washing(){ // Connect to power if(washer.connectToPower()){ // Open washing compartment washer.openLeftSide(); / Loading dirty clothes omitted / // Open water inlet washer.openWaterHole(); // Start water injection washer.startWaterInjection(); / Wait 5 minutes / // Stop water injection washer.stopWaterInjection(); / Adding detergent omitted / // Start washing washer.startWashing(); / Stop after 15 minutes */ washer.stopWashing(); } }

    /**

    • Automatic dewatering / public void dewashing(){ / Process to check if power is connected omitted */ // Open the right dewatering compartment washer.openRightSide(); // Start rotating the right dewatering compartment washer.startDewatering(); // Stop rotating the right dewatering compartment washer.stopDewatering();

      /*

      • Drainage process omitted
    • Power cut-off process omitted

      • */ } }

With the remote control, this is how we wash clothes:

package FacadePattern;

/**

  • @author ayqy

  • Test the semi-automatic washing machine applying the Facade Pattern (using remote control) */ public class Test implements Washer{

    public static void main(String[] args) { // Create old washing machine Washer washer = new Test(); // Create Facade (remote control) WasherFacade facade = new WasherFacade(washer); // Press wash button to start washing facade.washing(); /* Move clothes to the other side */ // Press dewater button to start dewatering facade.dewashing(); }

    /*

    • Ignore all these auto-generated things below...
    • */ @Override public boolean connectToPower() { // TODO Auto-generated method stub return false; }

    @Override public void openLeftSide() { // TODO Auto-generated method stub

    }

    @Override public void openWaterHole() { // TODO Auto-generated method stub

    }

    @Override public void startWaterInjection() { // TODO Auto-generated method stub

    }

    @Override public void stopWaterInjection() { // TODO Auto-generated method stub

    }

    @Override public void startWashing() { // TODO Auto-generated method stub

    }

    @Override public void stopWashing() { // TODO Auto-generated method stub

    }

    @Override public void openRightSide() { // TODO Auto-generated method stub

    }

    @Override public void startDewatering() { // TODO Auto-generated method stub

    }

    @Override public void stopDewatering() { // TODO Auto-generated method stub

    } }

Simply easy and comfortable. But looking closely, isn't it just defining a method to encapsulate method calls? What's so great about that? What's the difference from defining two methods in our new project code responsible for washing and dewatering? Of course, there is a difference; don't worry.

III. Advantages of the Facade Pattern

  1. Low Coupling

    First, look at our naming convention: the remote control is called WasherFacade. If we need to divide modules, it should be placed together with Washer, right? Correct. By defining Facade, we successfully decoupled Washer from our code. This means once Washer undergoes changes, we only need to modify the Facade, rather than searching for two methods in our lengthy project code.

  2. Protects Subsystem Encapsulation

    We did not open the well-encapsulated Washer to modify it; instead, we added some code to simplify the Washer's interface. Previously, callers understood the Washer's internals, but now they know almost nothing about Washer (except for the constructor).

  3. Suitable for Subsystems Containing Multiple Different Objects

    The Washer in the example is just a single object; it seems Washer itself should provide such a simple interface. But if we want to achieve semi-automation of daily life, we will face multiple objects, such as doors, windows, curtains, TV, microwave oven, washing machine, computer, etc. We hope for one-click breakfast preparation (automatically turn on lights, automatically start microwave heating), one-click nap (automatically close doors, automatically close curtains, automatically turn off lights), and other functions. The Facade Pattern is also applicable: we just need to let the Facade hold several concrete objects.

  4. Effectively Simplifies Subsystem Interfaces

    Previously, washing clothes required squatting beside the washing machine, constantly operating it. Now we can "complete it with one click." This is the simple, easy-to-use interface we want.

  5. Satisfies the "Law of Demeter"

    We achieved "talk only to friends." Our new system only knows the Facade, only talks to it, rather than running to talk to a bunch of low-level components in the subsystem.

IV. Summary

The Facade Pattern provides a simple, easy-to-use high-level interface for complex subsystems.

When you are struggling with many low-level components and can't break free, why not make a remote control? I think you may indeed need it...

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment