设计模式之外观模式

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

解释:是一种结构型模式,它主要解决的问题是:组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。在这里我想举一个例子:比如,现在有一辆汽车,我们(客户程序)要启动它,那我们就要发动引擎(子系统1),使四个车轮(子系统2)转动。但是实际中我们并不需要用手推动车轮使其转动,我们踩下油门,此时汽车再根据一些其他的操作使车轮转动。油门就好比系统给我们留下的接口,不论汽车是以何种方式转动车轮,车轮变化成什么牌子的,我们要开走汽车所要做的还是踩下油门。

结构图:


角色及其职责

外观角色(Facade:是模式的核心,他被客户client角色调用,知道各个子系统的功能。同时根据客户角色已有的需求预订了几种功能组合

子系统角色(Subsystem classes:实现子系统的功能,并处理由Facade对象指派的任务。对子系统而言,facadeclient角色是未知的,没有Facade的任何相关信息;即没有指向Facade的实例。

客户角色(client:调用facade角色获得完成相应的功能。

代码示例:

上面说的那个情形写一下实现代码,首先我们要实现三个子系统(WheelEngineBody):

子系统1Wheel

package com.jin.model.facade;

public class Wheel {
	public String WheelCircumrotate() {
		return "BMW's Wheel is Circumrotating";
	}

	public String WheelStop() {
		return "BMW's Wheel is stoped";
	}
}

子系统2Engine

package com.jin.model.facade;

public class Engine {
	public String EngineWork() {
		return "BMW's Engine is Working";
	}

	public String EngineStop() {
		return "BMW's Engine is stoped";
	}
}

子系统3Body

package com.jin.model.facade;

public class Body {
	public Wheel[] wheels = new Wheel[4];
	public Engine engine = new Engine();

	public Body() {
		for (int i = 0; i < wheels.length; i++) {
			wheels[i] = new Wheel();
		}
	}
}

外观角色:CarFacade

package com.jin.model.facade;

class CarFacade {
	Body body = new Body();

	public void Run() {
		System.out.println(body.engine.EngineWork());
		for (int i = 0; i < body.wheels.length; i++) {
			System.out.println(body.wheels[i].WheelCircumrotate());
		}
	}

	public void Stop() {
		System.out.println(body.engine.EngineStop());
		for (int i = 0; i < body.wheels.length; i++) {
			System.out.println(body.wheels[i].WheelStop());
		}
	}
}

客户端:Client

package com.jin.model.facade;

public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		CarFacade car = new CarFacade();
		car.Run();
		car.Stop();
	}
}

运行结果:

BMW's Engine is Working

BMW's Wheel is Circumrotating

BMW's Wheel is Circumrotating

BMW's Wheel is Circumrotating

BMW's Wheel is Circumrotating

BMW's Engine is stoped

BMW's Wheel is stoped

BMW's Wheel is stoped

BMW's Wheel is stoped

BMW's Wheel is stoped

正如上面所说:客户端代码(Program)不需要关心子系统,它只需要关心CarFacade所留下来的和外部交互的接口,而子系统是在CarFacade中聚合。

几个要点:

1、 从客户程序的角度看,Facade模式不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,从某种程度上也达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Facade接口的变化。

2、 Facade设计模式更注重从架构的层次去看整个系统,而不是单个类的层次。Facade很多时候更是一种架构设计模式。

使用场景

1)       在设计初期阶段,应该要有意识的将不同的两个层分离,比如经典的三层架构,就需要考虑在数据访问层、业务逻辑层和表示层的层与层建立外观Façade,这样可以为复杂的子系统提供一个简单的接口,使耦合大大降低。

2)       在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,大多数的模式使用时也都会产生很小的类,这本是好事,但也给外部调用它们的用户程序带来了使用上的困难,增加外观Façade可以提供一个简单的接口,减少它们之间的依赖。

3)       在维护一个遗留的大型系统时,可能这个系统已经难以维护和扩展了,但它包含非常重要的功能,新的需求开发必须要依赖于它,此时用外观模式Facade也是非常合适的。你可以为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Façade与遗留代码交互所有复杂的工作。


总结:

1)       根据“单一职责原则”,在软件中将一个系统划分为若干个子系统有利于降低整个系统的复杂性,一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小,而达到该目标的途径之一就是引入一个外观对象,它为子系统的访问提供了一个简单而单一的入口。

2)       外观模式也是“迪米特法则”的体现,通过引入一个新的外观类可以降低原有系统的复杂度,外观类充当了客户类与子系统类之间的“第三者”,同时降低客户类与子系统类的耦合度。外观模式就是实现代码重构以便达到“迪米特法则”要求的一个强有力的武器。

3)       外观模式要求一个子系统的外部与其内部的通信通过一个统一的外观对象进行,外观类将客户端与子系统的内部复杂性分隔开,使得客户端只需要与外观对象打交道,而不需要与子系统内部的很多对象打交道。

4)       外观模式从很大程度上提高了客户端使用的便捷性,使得客户端无须关心子系统的工作细节,通过外观角色即可调用相关功能。

5)       不要试图通过外观类为子系统增加新行为 ,不要通过继承一个外观类在子系统中加入新的行为,这种做法是错误的。外观模式的用意是为子系统提供一个集中化和简化的沟通渠道,而不是向子系统加入新的行为,新的行为的增加应该通过修改原有子系统类或增加新的子系统类来实现,不能通过外观类来实现。

6)       一个系统有多个外观类:在外观模式中,通常只需要一个外观类,并且此外观类只有一个实例,换言之它是一个单例类。在很多情况下为了节约系统资源,一般将外观类设计为单例类。当然这并不意味着在整个系统里只能有一个外观类,在一个系统中可以设计多个外观类,每个外观类都负责和一些特定的子系统交互,向用户提供相应的业务功能。

7)       抽象外观类的引入:外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。对于新的业务需求,不修改原有外观类,而对应增加一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时通过修改配置文件来达到不修改源代码并更换外观类的目的。


优点

1)       对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易。通过引入外观模式,客户代码将变得很简单,与之关联的对象也很少。

2)       实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。

3)       降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。

4)       只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。

缺点

1)       不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。

2)       在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值