Fork me on GitHub

设计模式之外观模式

前言

日常生活中我们想买一台电脑,一般来说有两种方式,一是通过电子市场购买电脑的各个配件进行组装,但这需要我们对电脑配件及其了解。当然,也有第二种方案,就是直接购买已经由装机公司安装完毕的整机,这也是大多数人的选择。

我们的进行软件开发过程中也会遇到类似的情况,在有A、B、C、D等多个模块的情况下,客户端需要与各个模块一一交互,极不方便,那么我们是否可以考虑采用类似”装机公司“这样的配置呢,我们接下来要讲的外观模式就类似“装机公司”。

一、模式实现

外观模式引入外观类,其中定义客户端要调用的方法,通过外观类分别调用各个模块实现功能,使得客户端交互变得简单。

外观类定义系统对外的接口,通过对多个模块的调用,将请求分配给子系统进行实现,模块是系统中实际进行功能实现的部分。

外观模式的结构如下所示:

现假设子系统内有A、B、C三个模块,则外观模式示例代码的的结构图如下所示:

下面为A、B、C三个模块的相关代码:

public interface MoudleA {
	public void test();
}
public class MoudleAImpl implements MoudleA {
	@Override
	public void test() {
		System.out.println("运行模块A的test方法");
	}
}

public interface MoudleB {
	public void test();
}
public class MoudleBImpl implements MoudleB {
	@Override
	public void test() {
		System.out.println("运行模块B的test方法");
	}
}

public interface MoudleC {
	public void test();
}
public class MoudleCImpl implements MoudleC {
	@Override
	public void test() {
		System.out.println("运行模块C的test方法");
	}
}

外观类的代码如下:

public class Facade {
	public void test() {
		MoudleA a = new MoudleAImpl();
		a.test();
		MoudleB b = new MoudleBImpl();
		b.test();
		new MoudleBImpl().test();
		MoudleC c = new MoudleCImpl();
		c.test();
	}
}

客户端代码如下:

public class Client {
	public static void main(String[] args) {
		new Facade().test();
	}
}

添加外观类,客户端只与外观类交互,不用了解系统内部实现细节,更好的实现客户端与系统的解耦。

二、模式说明

外观模式的本质是:封装交互,简化调用,其体现了最少知识原则,它的主要目的是减少外部与子系统内部模块的交互,松散耦合。外观类屏蔽了外部客户端与系统内部的交互,封装了系统内部的实现细节,方便了系统的修改,同时实现了对多个客户端功能的共享。通过外观模式实现了系统功能的步步拆分,加强了系统的重用性。

同时需要注意的是客户端若要实现自己的额功能也可以绕过外观类对系统内部的模块进行调用。

外观模式的调用序列图如下所示:

对于一个系统,外观类可以实现成为单例,也可将其作为外观辅助工具使用,将其中方法实现为静态方法,减少创建实例的步骤。

外观类一般不建议进行功能的实现,它是将请求转发给模块中的相应方法进行处理。

此外,外观类还可被实现为接口,在实现接口的同时需增加外观接口工厂,这增加了系统的复杂度,单也有额外的好处:

能够选择性的暴露接口的方法,减少模块对子系统外提供的接口方法。

下面用代码对此进行说明:

结构如上,下面为A、B、C三个模块的相关代码:

public interface MoudleA {
    public void a1();
    public void a2();
	public void test();
}
public interface MoudleB {
    public void b1();
     public void b2();
	public void test();
}
public interface MoudleC {
    public void c1();
     public void c2();
	public void test();
}

下面为外观类的代码:

public interface Facade {
    public void a1();
    public void b1();
    public void c1();
    
	public void test();
}

如a1、b1、c1方法提供给外部使用,外部客户端有需要直接调用外观类中的方法,然而实际的执行者是A、B、C三个模块,外部客户端不知道A、B、C模块的存在,实现了代码的隔离。

三、模式总结

1、使用场景

  • 为复杂子系统提供对外接口,简化客户端使用
  • 实现客户端程序与抽象类实现部分松散耦合,提高系统独立性和可移植性
  • 构建多层结构系统,使用外观类作为层间入口,简化层间调用,松散层间依赖关系

2、模式的优缺点

优点

  • 松散耦合。实现子系统与客户端解耦,系统内部模块更易扩展与维护。
  • 简单易用。客户端只需要与外观类交互即可,不用关注内部实现。
  • 易于划分访问层次。易于区分子系统中的队内对外方法,既方便客户端使用,也隐藏了内部实现细节。

缺点

当外观类设置不合理,会使得代码难以理解。

参考:文章主要参考《研磨设计模式》一书

posted @ 2019-01-30 23:40  紫焱luis  阅读(122)  评论(0编辑  收藏  举报