Facade外观模式(结构性模式)
1、系统的复杂度
需求:开发一个坦克模拟系统用于模拟坦克车在各种作战环境中的行为,其中坦克系统由引擎、控制器、车轮等各子系统构成.然后由对应的子系统调用.
常规的设计如下:
#region 坦克系统组成
/// <summary>
/// 引擎类
/// </summary>
public class Engine
{
public void EngineActionA() { } public void EngineActionB() { }
} /// <summary>
/// 车轮
/// </summary>
public class Wheel
{
public void WheelActionA() { } public void WheelActionB() { }
} /// <summary>
/// 控制器
/// </summary>
public class Controller
{
public void ControllerActionA() { } public void COntrollerActionB() { }
}
#endregion /// <summary>
/// 游戏系统
/// </summary>
public class GameSystem
{
/// <summary>
/// 引擎初始化类
/// </summary>
public class EngineInit
{
/// <summary>
/// 引擎初始化,并将控制权交给控制器
/// </summary>
public void Init()
{
var engine = new Engine();
var controller = new Controller();
}
} /// <summary>
/// 车轮初始化类
/// </summary>
public class WheelInit
{
/// <summary>
/// 车轮初始化,并将控制权交给控制器
/// </summary>
public void Init()
{
var engine = new Wheel();
var controller = new Controller();
}
}
}
ok,这是最简单的实现,完成了游戏系统对坦克系统的调用,将上面的系统调用抽象成一张构成图,如下:

可以发现,坦克系统的各个组成部分,柔和到了游戏系统的各个类型中,这种设计一旦坦克的组成部分发生变化,所造成的维护成本是十分昂贵的!
2、问题
组件(坦克系统)的客户端调用程序(系统系统)和组件中各种复杂的子系统之间产生了过多的耦合,随着外部客户程序和组件各子系统的演化,这种耦合产生的维护成本十分昂贵.
3、解决方案
必须抽象出一层接口,这层接口需要将坦克系统进行抽象,并告诉游戏客户端哪些功能,是它可以调用的,而不是让系统系统自己去调用坦克系统的组件来实现相关的功能,将组件系统(坦克系统)和外部调用客户程序(游戏系统)的变化之间的依赖解耦.将这种变化成本交给这层接口来承担.
#region 坦克系统组成
/// <summary>
/// 引擎类
/// </summary>
internal class Engine
{
public void EngineActionA() { } public void EngineActionB() { }
} /// <summary>
/// 车轮
/// </summary>
internal class Wheel
{
public void WheelActionA() { } public void WheelActionB() { }
} /// <summary>
/// 控制器
/// </summary>
internal class Controller
{
public void ControllerActionA() { } public void COntrollerActionB() { }
}
#endregion public class TankFacade
{
//注入相关坦克系统的组件,如果引擎、车轮这些可能会有风格的变化,可以考虑使用工厂模式来实现注入
Engine[] Engines = new Engine[];
Wheel[] Wheels = new Wheel[];
Controller Controller = new Controller(); /// <summary>
/// 坦克的启动功能,完成引擎、控制器的初始化.
/// </summary>
public void Start()
{ } /// <summary>
/// 坦克的停止功能,完成引擎、控制器的停止
/// </summary>
public void Stop()
{ }
}
客户端调用代码如下:
/// <summary>
/// 游戏系统
/// </summary>
public class GameSystem
{
private TankFacade tankFacade = null;
/// <summary>
/// 开始游戏
/// </summary>
public void Run()
{
TankFacade facade = new TankFacade();
facade.Start();
} /// <summary>
/// 结束游戏
/// </summary>
public void Stop()
{
if(tankFacade!=null)
tankFacade.Stop();
throw new Exception("引擎未启动,无法停止!");
}
}
通过TankFacade类,将坦克系统的组件集成到里面,提供给游戏系统它所需要的功能,很好的实现了客户端调用系统依赖与坦克组件的问题,完成了解耦.解耦后的结构图如下:

4、要点
(1)、从客户程序的角度来看,Facade模式补不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,达到了一种解耦的效果,内部子系统的变化不会影响到Facade接口的变化.
(2)、Facade模式更注重从架构的层次去看待整个系统,而不是单个类的层次,更多的时候是一种架构设计模式.
(3)、Facede模式与Apater模式、Bridge模式、Decorator模式的区别,Facede模式注重简化接口,Apater注重转换接口(将现有接口转换成客户需要的接口),Bridge模式接口的分离(即系统按照两个维度及以上的变化适合使用Bridge模式),Decorator模式注重稳定接口的情况下,为接口扩展功能.
Facade外观模式(结构性模式)的更多相关文章
- php设计模式之Proxy(代理模式)和Facade(外观)设计模式
Proxy(代理模式)和Facade(外观)设计模式它们均为更复杂的功能提供抽象化的概念,但这两种实现抽象化的过程大不相同 Proxy案例中,所有的方法和成员变量都来自于目标对象,必要时,该代理能够对 ...
- (转载)设计模式学习笔记(十一)——Facade外观模式
(转载)http://www.cnblogs.com/kid-li/archive/2006/07/10/446904.html Facade外观模式,是一种结构型模式,它主要解决的问题是:组件的客户 ...
- 设计模式(十一):FACADE外观模式 -- 结构型模式
1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子1:一个电源总开关可以控制四盏灯.一个风扇 ...
- 外观模式 门面模式 Facade 结构型 设计模式(十三)
外观模式(FACADE) 又称为门面模式 意图 为子系统中的一组接口提供一个一致的界面 Facade模式定义了一个高层接口,这一接口使得这一子系统更加易于使用. 意图解析 随着项目的持续发展,系统 ...
- NET设计模式 第二部分 结构性模式(11):外观模式(Façade Pattern)
外观模式(Façade Pattern) ——.NET设计模式系列之十二 Terrylee,2006年3月 概述 在软件开发系统中,客户程序经常会与复杂系统的内部子系统之间产生耦合,而导致客户程序随着 ...
- Facade - 外观模式
1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子1:一个电源总开关可以控制四盏灯.一个风扇 ...
- 设计模式10: Facade 外观模式(结构型模式)
Facade 外观模式(结构型模式) 系统的复杂度 假设我们要开发一个坦克模式系统用于模拟坦克车在各种作战环境中的行为,其中坦克系统由引擎.控制器.车轮.车身等各个子系统构成. internal cl ...
- Facade——外观模式
Facade外观模式,也是比较常用的一种模式,基本上所有软件系统中都会用到. GOF 在<设计模式>一书中给出如下定义:为子系统中的一组接口提供一个一致的界面, Facade 模式定义了一 ...
- 设计模式在实际业务应用中的介绍之3——外观或门面模式Facade对AOP装配业务工厂的应用
在C#中实现的基于外观或门面模式打造的业务应用案例 以前一直没有想过写一些东西来把项目中用到的知识点及技术实现做一个归纳整理并分享出来.现在打算逐渐的把项目中的一些东西整理并分享出来,与大家共勉! 外 ...
随机推荐
- IntellJ IDEA 2017 激活编译器配置,读取多个配置文件
1.设置编译器,找到1,点击2 2.输入设置命令:--spring.profiles.active=test,如果是多个文件输入--spring.profiles.active=test,dev 3. ...
- 第01章:MongoDB简介
①MongoDB是什么 MongoDB是一个使用C++编写的.开源的.面向文档的NoSQL(Not Only SQL)数据库,也是当前最热门的NoSql数据库之一. ②MongoDB特点 1.高性能. ...
- 如何使用阿里巴巴iconfont矢量图片
①打开此网站http://www.iconfont.cn/ , 选择需要的几个图形 → 加入购物车 → 添加至项目 → 给项目随便命名 → 点击电线连接并点击代码 → 复制代码到css ②在body里 ...
- HDMI之(AVI)Auxiliary Video Information InfoFrame
这是HDMI协议中关于AVI接口的信息 AVI InfoFrame在H14b中进行了定义.从HDMI 2.0 10.1 Use of the AVI InfoFrame in This Spe ...
- How to temporally disable IDE tools (load manually)
It is possible to prevent the IDE Tools from being loaded automatically when starting Visual Studio. ...
- MFC载入JPG图片
## 1.定义画图函数 HRESULT CIPCamDlg::draw(char *lpImageFile, HWND hWnd, int nScrWidth, int nScrHeight) { H ...
- Android FragmentActivity 嵌套 Fragment 调用startActivityForResult返回的requestCode错误
Android FragmentActivity 嵌套 Fragment 调用startActivityForResult返回的requestCode错误 此时,要在调用startActivityFo ...
- 第78讲:Type与Class实战详解
今天来学习下type与class解析 让我们先来看看代码 import scala.reflect.runtime.universe._ class Sparktrait Hadoopobject F ...
- 二分搜素——(lower_bound and upper_bound)
因为每个人二分的风格不同,所以在学习二分的时候总是被他们的风格搞晕.有的人二分风格是左闭右开也就是[L,R),有的人是左开右闭的(L,R]. 二分的最基本条件是,二分的序列需要有单调性. 下面介绍的时 ...
- hive中数据存储格式对比:textfile,parquent,orc,thrift,avro,protubuf
这篇文章我会从业务中关注的: 1. 存储大小 2.查询效率 3.是否支持表结构变更既数据版本变迁 5.能否避免分隔符问题 6.优势和劣势总结 几方面完整的介绍下hive中数据以下几种数据格式:text ...