外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用,它是一种对象结构型模式。
Facade类:外观类,知道哪些子系统类负责处理请求,将客户的请求代理给适当的子系统对象。
SubSystem Classes:子系统类集合,实现子系统的功能,处理Facade对象指派的任务。注意子类中没有Facade对象指派的任务。注意子类中没有Facade的任何信息,即没有对Facade对象的引用。每一个子系统都可以被客户端直接调用,或者被Facade直接调用。子系统并不知道Facade的存在,对于子系统而言,Facade仅仅是另一个客户端而已。
假设一个股民买了四支股票,分别为股票一、股票二、国债股和房地产股,然后这个股民要对这四个股票进行买入和赎回的操作,如果要使用一般的方法进行操作,那么操作代码如下:
Stock1类(具体股票一类):
package com.jxs.facade;
/**
* Created by jiangxs on 2018/5/7.
*
* 股票1
*/
public class Stock1 {
// 卖股票
public void sell() {
System.out.println("股票1卖出");
}
// 买股票
public void buy() {
System.out.println("股票1买入");
}
}
Stock2(具体股票二类):
package com.jxs.facade;
/**
* Created by jiangxs on 2018/5/7.
*
* 股票2
*/
public class Stock2 {
// 卖股票
public void sell() {
System.out.println("股票2卖出");
}
// 买股票
public void buy() {
System.out.println("股票2买入");
}
}
NationalDebt1类(具体国债类):
package com.jxs.facade;
/**
* Created by jiangxs on 2018/5/7.
*
* 国债1
*/
public class NationalDebt1 {
// 卖国债
public void sell() {
System.out.println("国债1卖出");
}
// 买国债
public void buy() {
System.out.println("国债1买入");
}
}
Realty1类(具体房地产类):
package com.jxs.facade;
/**
* Created by jiangxs on 2018/5/7.
*
* 房地产1
*/
public class Realty1 {
// 卖房地产
public void sell() {
System.out.println("房地产1卖出");
}
// 买房地产
public void buy() {
System.out.println("房地产1买入");
}
}
客户端:
package com.jxs.facade;
/**
* Created by jiangxs on 2018/5/7.
*/
public class Client {
public static void main(String[] args) {
Stock1 s1 = new Stock1();
Stock2 s2 = new Stock2();
NationalDebt1 n1 = new NationalDebt1();
Realty1 r1 = new Realty1();
s1.buy();
s2.buy();
n1.buy();
r1.buy();
s1.sell();
s2.sell();
n1.sell();
r1.sell();
}
}
运行结果:
股票1买入
股票2买入
国债1买入
房地产1买入
股票1卖出
股票2卖出
国债1卖出
房地产1卖出
Process finished with exit code 0
虽然这样做也满足了需求,但是我们可以看到在客户端中要创建大量的对象,并且需要具体参与每支股票的买卖,耦合性很高。我们完全可以让这个股民买一致基金,让这个基金去管理这些股票,这个股民无需关注每支股票到底要怎么样操作,他只需要买了基金,让基金去管这些,他只用抽烟喝酒烫头就行了,过段时间再赎回基金就可以有大把的money,此时客户端就可以非常简洁。要想达到这样的效果,就要使用我们的外观模式啦。
我们先来看看这个例子的结构图:
然后使用代码来实现:
具体的股票类上面代码已经给出,这里不再重复。
Fund类(基金类):
package com.jxs.facade;
/**
* Created by jiangxs on 2018/5/7.
*/
public class Fund {
Stock1 s1;
Stock2 s2;
NationalDebt1 n1;
Realty1 r1;
public Fund() {
s1 = new Stock1();
s2 = new Stock2();
n1 = new NationalDebt1();
r1 = new Realty1();
}
public void buyFund() {
s1.buy();
s2.buy();
n1.buy();
r1.buy();
}
public void sellFund() {
s1.sell();
s2.sell();
n1.sell();
r1.sell();
}
}
客户端:
package com.jxs.facade;
/**
* Created by jiangxs on 2018/5/7.
*/
public class Client {
public static void main(String[] args) {
Fund fund = new Fund();
// 基金购买
fund.buyFund();
// 基金赎回
fund.sellFund();
}
}
运行结果:
股票1买入
股票2买入
国债1买入
房地产1买入
股票1卖出
股票2卖出
国债1卖出
房地产1卖出
Process finished with exit code 0
①引入外观模式,是客户对子系统的使用变得简单了,减少了与子系统的关联对象,实现了子系统与客户之间的松耦合关系。
②只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。
③降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程。
①不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。
②在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
①在设计初期阶段,应该有意识的将不同的两个层分离。比如经典的MVC三层架构,就需要考虑在Control层和Model层,Model层和View层的层与层之间建立外观Facade,这样就可以为复杂子系统提供一个简单的接口,使得耦合大大降低。
②在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,大多数的模式使用时也都会产生很多很小的类,这本是好事,但也给外部调用它们的用户程序带来了使用上的困难,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。
③在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为它包含了非常重要的功能,新的需求开发必须要依赖于它。此时用外观模式Facade也是非常合适的。你可以为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。
注:
以上代码均可在github上进行下载:https://github.com/xsongj/designPattern
参考:《大话设计模式》