设计模式之外观模式
定义
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式核心
为子系统提供统一的入口。封装子系统的复杂性,便于客户端调用。
角色分类
(1)外观(Facade)角色 :客户端可以调用这个角色的方法。此角色知晓相关子系统的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。
(2)子系统(SubSystem)角色 :可以同时有一个或者多个子系统。每个子系统都不是一个单独的类,而是一个类的集合。每个子系统都可以被客户端直接调用,或者被外观角色调用。子系统并不知道外观角色的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。
例子:注册公司
不使用外观模式的类图
代码
子系统角色,多个类组成
public interface 税务局 {
void taxCertificate(); //办理税务登记证
}
class 海淀税务局 implements 税务局 {
@Override
public void taxCertificate() {
System.out.println("在海淀税务局办理税务登记证!");
}
}
public interface 银行 {
void openAccount(); //开户
}
class 中国工商银行 implements 银行 {
@Override
public void openAccount() {
System.out.println("在中国工商银行开户!");
}
}
public interface 质检局 {
void orgCodeCertificate(); //办理组织机构代码证
}
class 海淀质检局 implements 质检局 {
@Override
public void orgCodeCertificate() {
System.out.println("在海淀区质检局办理组织机构代码证!");
}
}
public interface 工商局 {
void checkName(); //核名
}
class 海淀区工商局 implements 工商局 {
@Override
public void checkName() {
System.out.println("检查名字是否有冲突!");
}
}
客户端测完类
public class Client1 {
public static void main(String[] args) {
工商局 a = new 海淀区工商局();
a.checkName();
质检局 b = new 海淀质检局();
b.orgCodeCertificate();
税务局 c = new 海淀税务局();
c.taxCertificate();
银行 d = new 中国工商银行();
d.openAccount();
}
}
结果
使用外观模式的类图
代码
子系统角色,多个类组成
public interface 税务局 {
void taxCertificate(); //办理税务登记证
}
class 海淀税务局 implements 税务局 {
@Override
public void taxCertificate() {
System.out.println("在海淀税务局办理税务登记证!");
}
}
public interface 银行 {
void openAccount(); //开户
}
class 中国工商银行 implements 银行 {
@Override
public void openAccount() {
System.out.println("在中国工商银行开户!");
}
}
public interface 质检局 {
void orgCodeCertificate(); //办理组织机构代码证
}
class 海淀质检局 implements 质检局 {
@Override
public void orgCodeCertificate() {
System.out.println("在海淀区质检局办理组织机构代码证!");
}
}
public interface 工商局 {
void checkName(); //核名
}
class 海淀区工商局 implements 工商局 {
@Override
public void checkName() {
System.out.println("检查名字是否有冲突!");
}
}
外观类角色
/**
* 办理注册公司流程的门面对象(Facade类)
* @author mama
*
*/
public class RegisterFacade {
public void register(){
工商局 a = new 海淀区工商局();
a.checkName();
质检局 b = new 海淀质检局();
b.orgCodeCertificate();
税务局 c = new 海淀税务局();
c.taxCertificate();
银行 d = new 中国工商银行();
d.openAccount();
}
}
客户端测试
public class Client1 {
public static void main(String[] args) {
new RegisterFacade().register();
}
}
结果
RegisterFacade 类其实相当于子系统类的外观界面,有了这个Facade类,那么客户端就不需要亲自调用子系统中的那些具体实现的子类了,也不需要知道系统内部的实现细节,甚至都不需要知道这些子类的存在,客户端只需要跟Facade类交互就好了,从而更好地实现了客户端和子系统中具体类的解耦,让客户端更容易地使用系统。
优点
(1)实现了子系统与客户端之间的松耦合关系
(2)减少客户端所需处理的对象数目,使得子系统使用起来更加容易。
(3)一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
缺点
(1)不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性。
(2)如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则。
适用场景
(1)首先在设计初期阶段,应该要有意识的将不同的两个层分离,比如经典的三层架构,就需要考虑在数据访问和业务逻辑层、业务逻辑层和表示层的层与层之间建立外观接口Facade,这样可以为每一层复杂的子系统提供一个简单的接口,不仅使得耦合大大降低,也让外部调用更简单。
(2)其次,在开发阶段,子系统往往因为不断的重构演化而变化得越来越复杂,大多数的模式使用时也都会产生很多很小的类,这本是好事,但也会给外部调用它们的用户带来了使用上的困难,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。
(3)第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为它包含非常重要的功能,新的需求开发必须要依赖它,此时用外观模式也是非常适合的。你可以为新系统开发一个外观Facade类,来为这个设计粗糙或高度复杂的遗留代码提供一个比较清晰简单的接口,让新系统与Facade对象交互,Facade对象则与遗留代码交互所有复杂的工作。