外观模式 详解

定义

为子系统中的一组接口提供一个统一的入口,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

角色

  • 外观角色(Facade):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常的情况下,它将所有从客户端发来的请求委派到相应的子系统,传递给相应的子系统对象处理;
  • 子系统角色(Subsystem classes):通常有一到多个子系统角色,每一个子系统角色可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观角色传送过来的请求;子系统并不知道外观角色的存在,对于子系统而言,外观角色仅仅是另一个客户端而已
  • 客户角色(ConcreteStrategy): 调用外观角色提供的接口,完成相应的功能;

从网上找到的例图
enter image description here

enter image description here

适用场景

  • 当你要为一个复杂子系统提供一个简单接口的时候;

    在开发中 ,子系统往往会因为不断的演化而变得更加复杂,大多数模式使用时都会产生更多更小的类,这虽然能使得子系统更具有可重用性,也容易对子系统进行定制,但是这也会给那些不需要定制子系统的用户带来一些使用上的困难;但是,Facade可以提供一个简单的接口,而那些需要更多的可定制性的用户可以越过Facade层;

  • 客户程序与抽象类的实现部分之间存在很大的依赖性;引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性;

  • 当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点;如果子系统之间是相互依赖的,你可以让它们仅通过Facade进行通讯,从而简化它们之间的依赖关系;

例子

比如一个房间有一盏灯,一个空调,一个电脑,里面的电器则是房间的子系统,这个房间算是一个子系统,一层楼又有多个房间,一个大厦又有n层楼,可以说一个大厦是总系统,下面都是小的子系统;当客户要关掉房间的所有电器,可以是可以,但是非常麻烦,这个时候就需要一个总闸,关掉总闸,大厦所有的楼的灯就关掉了,总闸就相当于外观角色;


实现代码


/**
 * Created by George on 16/6/25.
 */

//子系统
function Eletricity()
{
    this.cost = 100;
};
Eletricity.prototype.PayEletricity = function(peole)
{
    console.log("pay eletricity...");
    peole.PayMoney(this.cost);
};

function NetWork()
{
    this.cost = 100;
};
NetWork.prototype.PayNetWork = function(peole)
{
    console.log("pay network...");
    peole.PayMoney(this.cost);
};

function Water()
{
    this.cost = 100;
};
Water.prototype.PayWater = function(peole)
{
    console.log("pay water...");
    peole.PayMoney(this.cost);
};

//客户端
function People()
{
    this.money = 500;
};
People.prototype.PayMoney = function (money) {
    console.log("people pay the money $" + money);
    this.money -= money;
    console.log("people left the money $" + this.money);
};

//外观角色
function Facade()
{
    this.eletricity = new Eletricity();
    this.network = new NetWork();
    this.water = new Water();
    this.money = 0;
};
Facade.prototype.PayAll = function (people) {
    people.PayMoney(this.GetAllMoney());
    this.money += this.GetAllMoney();
    this.eletricity.PayEletricity(this);
    this.network.PayNetWork(this);
    this.water.PayWater(this);
    this.money = 0;
};
Facade.prototype.GetAllMoney = function () {
    return this.eletricity.cost + this.network.cost + this.water.cost;
};
Facade.prototype.PayMoney = function (money){
    console.log("facade pay the money $" + money);
    this.money -= money;
    console.log("facade left the money $" + this.money);
};

//使用外观模式
var people = new People();
var facade = new Facade();
facade.PayAll(people);

//没有使用外观模式
people = new People();
var eletricity = new Eletricity();
var network = new NetWork();
var water = new Water();
eletricity.PayEletricity(people);
network.PayNetWork(people);
water.PayWater(people);

外观模式运行代码:
这里写图片描述

这上面的代码其实就是支付宝帮用户付了电费,网费,水费,而不需要用户亲自到一个地方付相应的费用,相当方便;
这里的支付宝计算好了总的价钱,收了客户的钱,再把这些钱都交到相应的地方;


优缺点

注意的是
1. 不能很好地限制客户使用子系统类,而且如果对客户访问子系统做过多的限制又会减少了可变性和灵活性;
2. 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的代码,违背了“开闭原则”;


比较中介者模式

  1. 中介者模式中的同事角色都知道中间有个中介者的存在,但是外观模式则不知道外观角色;
  2. 中介者模式是行为模式,而外观模式则是结构模式。
  3. 两者具体做的事情也不一样,前者用一个中介对象来封装一系列同事对象的交互行为,由中心协调同事类和中心本身共同完成业务;
    而外观模式则是对子系统提供统一接口,所有的请求处理都委托给子系统完成;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值