设计模式文档无水印可复制

一、外观模式概述

1.1 什么是外观模式

外观模式(Facade Pattern)是一种结构型设计模式,这种模式通过为多个复杂的子系统提供一个一致的接口,来隐藏系统的复杂性,从而使得这些子系统更加容易被访问。该模式的主要意图是为子系统中的一组接口提供一个一致的界面,定义了一个高层接口,使得这一子系统更加容易使用。

外观模式在日常开发中是经常被使用的一种设计模式,它通过引入一个外观角色,简化了客户端与子系统之间的交互关系,为复杂的子系统调用提供一个统一的入口,降低了客户端的使用难度。

1.2 简单实现外观模式

// 定义一个外观类
public class Facade {
    private SubSystemA subSystemA;
    private SubSystemB subSystemB;
    private SubSystemC subSystemC;

    public Facade() {
        subSystemA = new SubSystemA();
        subSystemB = new SubSystemB();
        subSystemC = new SubSystemC();
    }

    // 定义一个简单易用的接口
    public void operation() {
        subSystemA.operation1();
        subSystemB.operation2();
        subSystemC.operation3();
    }
}

// 定义三个子系统类
class SubSystemA {
    public void operation1() {
        System.out.println("SubSystemA operation1");
    }
}

class SubSystemB {
    public void operation2() {
        System.out.println("SubSystemB operation2");
    }
}

class SubSystemC {
    public void operation3() {
        System.out.println("SubSystemC operation3");
    }
}

在客户端代码中,我们只需要创建一个外观类的实例,然后调用其 operation 方法即可:

public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.operation(); // 输出 "SubSystemA operation1"、"SubSystemB operation2"、"SubSystemC operation3"
    }
}

1.3 使用外观模式的注意事项

  • 1、外观模式的关键是提供一个一致的接口,使得客户端可以更加简单地与子系统进行交互,而不需要了解子系统内部的复杂性。因此,在设计外观类时,应该尽量将客户端可能需要使用的功能都包含在内,同时避免添加不必要的功能。

  • 2、另一个要注意的是,虽然外观模式可以降低客户端和子系统之间的耦合度,但同时也增加了外观类和子系统之间的耦合度。这意味着如果子系统中的某个模块发生了改变,可能也需要对外观类进行相应的修改。因此,在使用外观模式时,要尽量减少外观类和子系统类之间的依赖关系,让子系统更加地独立和灵活。

  • 3、当子系统数量增加时,外观类可能会变得非常复杂。在这种情况下,可以考虑将外观类拆分成多个部分,每个部分负责一部分子系统的接口调用。这样不仅可以提高代码的可读性和可维护性,而且可以让子系统之间的耦合度更低。

  • 4、最后,使用外观模式时需要合理地划分访问层次。例如,可以将一些常用的功能放在高层接口中,而不常用的功能则放在底层实现中。这样既可以提高代码的效率,又可以减少出错的可能性。

二、外观模式的用途

  • 1、简化调用:外观模式能够简化复杂系统的调用过程,客户端无需对子系统进行深入了解,即可完成调用。这种简化的过程降低了客户端的使用难度,提高了代码的可读性和易用性。

  • 2、降低耦合:使用外观模式后,客户端只需要与外观对象进行交互,而不需要与复杂的子系统直接进行交互。这样可以有效地降低系统间的依赖,减小了系统间的耦合度,使得子系统更加地独立和灵活。

  • 3、提高安全性:由于客户端不直接与子系统进行交互,而是通过外观类进行的,因此可以有效地防止对子系统的误操作,提高了系统的安全性。

  • 4、提高灵活性和可维护性:当子系统数量增加时,外观类可能会变得非常复杂。在这种情况下,可以考虑将外观类拆分成多个部分,每个部分负责一部分子系统的接口调用。这样不仅可以提高代码的可读性和可维护性,而且可以让子系统之间的耦合度更低。

三、外观模式实现方式

3.1 简单外观模式(Simple Facade Pattern)

// 定义一个接口
interface SubSystem {
    void operation();
}

// 实现接口的具体类
class ConcreteSubSystemA implements SubSystem {
    @Override
    public void operation() {
        System.out.println("执行子系统A的操作");
    }
}

class ConcreteSubSystemB implements SubSystem {
    @Override
    public void operation() {
        System.out.println("执行子系统B的操作");
    }
}

class ConcreteSubSystemC implements SubSystem {
    @Override
    public void operation() {
        System.out.println("执行子系统C的操作");
    }
}

// 外观类,用于封装子系统的调用
class Facade {
    private SubSystem subSystemA;
    private SubSystem subSystemB;
    private SubSystem subSystemC;

    public Facade() {
        subSystemA = new ConcreteSubSystemA();
        subSystemB = new ConcreteSubSystemB();
        subSystemC = new ConcreteSubSystemC();
    }

    public void executeOperation() {
        subSystemA.operation();
        subSystemB.operation();
        subSystemC.operation();
    }
}

// 测试代码
public class FacadePatternDemo {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.executeOperation(); // 输出 "执行子系统A的操作"、"执行子系统B的操作"、"执行子系统C的操作"
    }
}

3.2 经典外观模式(Classic Facade Pattern)

经典外观模式(Facade Pattern)是一种结构型设计模式,它为子系统中的一组接口提供一个统一的高层接口。外观模式定义了一个高层接口,这个接口使得子系统更容易使用。

下面是一个简单的Java实现经典外观模式的例子:

首先,我们创建一个表示操作系统的类OperatingSystem,它包含了一些底层操作的方法,如启动、关闭等。

public class OperatingSystem {
    public void start() {
        System.out.println("启动操作系统");
    }

    public void shutdown() {
        System.out.println("关闭操作系统");
    }
}

接下来,我们创建一个外观类Facade,它也包含了一些底层操作的方法,但为了简化调用,我们只提供了启动和关闭操作系统的方法。

public class Facade {
    private OperatingSystem operatingSystem;

    public Facade() {
        operatingSystem = new OperatingSystem();
    }

    public void start() {
        System.out.println("外观模式开始启动操作系统");
        operatingSystem.start();
    }

    public void shutdown() {
        System.out.println("外观模式开始关闭操作系统");
        operatingSystem.shutdown();
    }
}

最后,我们在客户端代码中使用外观类来启动和关闭操作系统。

public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.start();
        facade.shutdown();
    }
}

运行客户端代码,输出结果如下:

外观模式开始启动操作系统
启动操作系统
外观模式开始关闭操作系统
关闭操作系统

通过这个例子,我们可以看到外观模式将复杂的子系统操作封装在一个简单的高层接口中,使得客户端代码更容易使用。

3.3 代理外观模式(Proxy Facade Pattern)

代理外观模式是一种结构型设计模式,它为子系统中的一组接口提供一个统一的高层接口。代理外观模式包含一个代理类和一个真实类。代理类负责在客户端与真实类之间进行通信,真实类负责实现具体的业务逻辑。

下面是一个简单的Java实现代理外观模式的例子:

首先,创建一个真实类RealSubject,它实现了一个接口Subject。

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("真实主题执行请求");
    }
}

然后,创建一个代理类Proxy,它也实现了Subject接口。在代理类中,持有一个真实类的引用,并在代理类的方法中调用真实类的方法。

public class Proxy implements Subject {
    private RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("代理主题执行请求前的操作");
        realSubject.request();
        System.out.println("代理主题执行请求后的操作");
    }
}

最后,在客户端代码中使用代理类来调用真实类的方法。

public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);
        proxy.request();
    }
}

运行客户端代码,输出结果如下:

代理主题执行请求前的操作
真实主题执行请求
代理主题执行请求后的操作

通过这个例子,我们可以看到代理外观模式将复杂的子系统操作封装在一个简单的高层接口中,使得客户端代码更容易使用。

3.4 组合外观模式(Composite Facade Pattern)

组合外观模式(Composite Pattern)是一种结构型设计模式,它允许将对象组合成树形结构以表示“部分-整体”的层次结构。组合外观模式使得客户端代码与子系统的实现解耦,可以统一地处理整个层次结构。

下面是一个简单的Java实现组合外观模式的例子:

首先,创建一个抽象组件类Component,它定义了组件的共同接口。

public abstract class Component {
    public void operation() {
    }
}

然后,创建具体组件类ConcreteComponent,它实现了Component接口。

public class ConcreteComponent extends Component {
    @Override
    public void operation() {
        System.out.println("具体组件执行操作");
    }
}

接下来,创建装饰器基类Decorator,它也实现了Component接口,并持有一个Component类型的成员变量。

public abstract class Decorator extends Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        if (component != null) {
            component.operation();
        }
    }
}

创建具体装饰器类ConcreteDecoratorA和ConcreteDecoratorB,它们分别继承自Decorator类,并在operation方法中添加额外的功能。

public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedFunction();
    }

    private void addedFunction() {
        System.out.println("具体装饰器A添加的功能");
    }
}

public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedFunction();
    }

    private void addedFunction() {
        System.out.println("具体装饰器B添加的功能");
    }
}

最后,在客户端代码中使用组合外观模式来组合组件。

public class Client {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        Component decoratorA = new ConcreteDecoratorA(component);
        Component decoratorB = new ConcreteDecoratorB(decoratorA);
        decoratorB.operation();
    }
}

运行客户端代码,输出结果如下:

具体组件执行操作
具体装饰器A添加的功能
具体装饰器B添加的功能

通过这个例子,我们可以看到组合外观模式将具体的组件和装饰器组合在一起,使得客户端代码可以统一地处理整个层次结构。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐