设计模式之外观模式(Facade Pattern)

一.什么是外观模式?

简单的说,外观模式是用来简化接口的。

通常,我们觉得一个子系统不好用,可能是因为它提供的外部接口太接近低层组件,让我们用起来感到很麻烦。

因为我们不需要知道内部细节,我们只想要一个“一键完成”功能,调用子系统的某个方法,它可能替我们完成了图片预处理,而不是靠我们自己来调用灰度化方法、图像增强算法、噪声处理方法等等来一步步实现预处理。

如果子系统提供的接口太接近低层组件,不仅不易用,而且破坏了子系统的封装(想调用子系统就必须了解其各个低层组件,我们被迫知道了太多不应该知道的细节。。)

二.举个例子

假设有一个封装好的老式洗衣机,它提供了这些对外接口:

package FacadePattern;

/**
 * @author ayqy
 * 定义洗衣机接口
 */
public interface Washer {
	/*
	 * 公共部分
	 * */
	//连接电源
	public abstract boolean connectToPower();

	/*
	 * 洗涤部分
	 * */
	//打开左侧的洗涤舱
	public abstract void openLeftSide();
	//打开注水口
	public abstract void openWaterHole();
	//开始注水
	public abstract void startWaterInjection();
	//停止注水
	public abstract void stopWaterInjection();
	//开始旋转左侧洗涤舱
	public abstract void startWashing();
	//停止旋转左侧洗涤舱
	public abstract void stopWashing();

	/*
	 * 脱水部分
	 * */
	//打开右侧的脱水舱
	public abstract void openRightSide();
	//开始旋转右侧脱水舱
	public abstract void startDewatering();
	//停止旋转右侧脱水舱
	public abstract void stopDewatering();

	/*
	 * 排水部分省略。。
	 * */
}

没办法,它实在太老了,不能满足我们的现代生活,但我们又买不起新的自动化洗衣机,所以我们需要把它变成一个半自动的洗衣机,用节省下来的时间去写代码。。

先看看我们是如何用老式洗衣机来洗衣服的:

package FacadePattern;

/**
 * @author ayqy
 * 使用老式洗衣机来洗衣服
 */
public class Washing implements Washer{

	public static void main(String[] args) {
		//创建洗衣机对象
		Washer washer = new Washing();
		//连接电源
		if(washer.connectToPower()){
			//打开洗涤舱
			washer.openLeftSide();
			/*装入脏衣服过程省略*/
			//打开注水口
			washer.openWaterHole();
			//开始注水
			washer.startWaterInjection();
			/*等待5分钟*/
			//停止注水
			washer.stopWaterInjection();
			/*添加洗涤剂过程省略*/
			//开始洗涤
			washer.startWashing();
			/*15分钟后停止*/
			washer.stopWashing();

			/*
			 * 脱水部分省略
			 * */
		}
	}

	/*
	 * 忽略下面自动生成的这些东西。。
	 * */
	@Override
	public boolean connectToPower() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void openLeftSide() {
		// TODO Auto-generated method stub

	}

	@Override
	public void openWaterHole() {
		// TODO Auto-generated method stub

	}

	@Override
	public void startWaterInjection() {
		// TODO Auto-generated method stub

	}

	@Override
	public void stopWaterInjection() {
		// TODO Auto-generated method stub

	}

	@Override
	public void startWashing() {
		// TODO Auto-generated method stub

	}

	@Override
	public void stopWashing() {
		// TODO Auto-generated method stub

	}

	@Override
	public void openRightSide() {
		// TODO Auto-generated method stub

	}

	@Override
	public void startDewatering() {
		// TODO Auto-generated method stub

	}

	@Override
	public void stopDewatering() {
		// TODO Auto-generated method stub

	}

}

仅仅演示了一个洗衣服的过程,我们就调用了那么多操作,而且我们必须知道这台洗衣机的内部细节,不然根本无法使用它。。

洗衣服可能需要60分钟(注水 + 洗涤 + 脱水 + 排水),在这期间我们几乎什么事情也做不了,只能蹲在洗衣机旁边不停的操作机器

-------

我想,我们可能需要一个遥控器,上面有2个按钮:

  • 洗涤
  • 脱水

然后我们洗衣服的过程会变成这样:

  1. 摁洗涤按钮,自动连接电源,自动打开洗涤舱,自动注水5分钟,自动开始洗涤15分钟
  2. 摁脱水按钮,自动打开脱水舱,自动脱水10分钟,自动排水,自动断开电源

这简直太棒了,我们可以在吃午餐前摁一下洗涤按钮,吃完之后去把衣服拿到右侧,再摁一下脱水按钮,然后去上班,下午回来之后把衣服晾起来就好了

(当然,手动把衣服从左侧拿到右侧的过程是避免不了的,毕竟它太老了,想变成全自动洗衣机是不可能的。。)

来看看我们自己做的遥控器:

package FacadePattern;

/**
 * @author ayqy
 * 遥控器(也就是所谓的外观)
 */
public class WasherFacade {
	private Washer washer;

	public WasherFacade(Washer washer){
		this.washer = washer;
	}

	/**
	 * 自动洗涤
	 */
	public void washing(){
		//连接电源
		if(washer.connectToPower()){
			//打开洗涤舱
			washer.openLeftSide();
			/*装入脏衣服过程省略*/
			//打开注水口
			washer.openWaterHole();
			//开始注水
			washer.startWaterInjection();
			/*等待5分钟*/
			//停止注水
			washer.stopWaterInjection();
			/*添加洗涤剂过程省略*/
			//开始洗涤
			washer.startWashing();
			/*15分钟后停止*/
			washer.stopWashing();
		}
	}

	/**
	 * 自动脱水
	 */
	public void dewashing(){
		/*判断是否已连接电源过程省略*/
		//打开右侧的脱水舱
		washer.openRightSide();
		//开始旋转右侧脱水舱
		washer.startDewatering();
		//停止旋转右侧脱水舱
		washer.stopDewatering();

		/*
		 * 排水过程省略
		 * 切断电源过程省略
		 * */
	}
}

有了遥控器之后,我们是这样洗衣服的:

package FacadePattern;

/**
 * @author ayqy
 * 测试应用了外观模式的半自动洗衣机(利用遥控器)
 */
public class Test implements Washer{

	public static void main(String[] args) {
		//创建老式洗衣机
		Washer washer = new Test();
		//创建外观(遥控器)
		WasherFacade facade = new WasherFacade(washer);
		//按下洗涤按钮开始洗衣服
		facade.washing();
		/*把衣服拿到另一侧*/
		//按下脱水按钮开始脱水
		facade.dewashing();
	}

	/*
	 * 忽略下面这些自动生成的东西。。
	 * */
	@Override
	public boolean connectToPower() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void openLeftSide() {
		// TODO Auto-generated method stub

	}

	@Override
	public void openWaterHole() {
		// TODO Auto-generated method stub

	}

	@Override
	public void startWaterInjection() {
		// TODO Auto-generated method stub

	}

	@Override
	public void stopWaterInjection() {
		// TODO Auto-generated method stub

	}

	@Override
	public void startWashing() {
		// TODO Auto-generated method stub

	}

	@Override
	public void stopWashing() {
		// TODO Auto-generated method stub

	}

	@Override
	public void openRightSide() {
		// TODO Auto-generated method stub

	}

	@Override
	public void startDewatering() {
		// TODO Auto-generated method stub

	}

	@Override
	public void stopDewatering() {
		// TODO Auto-generated method stub

	}

}

简直轻松惬意,不过仔细一看,不就是定义了一个方法来封装方法调用嘛,有什么了不起的?与在我们的新项目代码中建立定义两个方法负责洗涤和脱水有什么区别吗?

当然有,不要着急

三.外观模式的优点

1.低耦合

先看看我们的命名方式,遥控器叫做WasherFacade,如果要划分模块,它应该与Washer放在一起吧

没错,通过定义Facade,我们成功解耦了Washer与我们的代码,意味着一旦Washer发生变更,我们直接修改Facade就好了,而不是在我们冗长的项目代码里寻找某两个方法

2.保护了子系统的封装

我们并没有打开封装好的Washer去修改,而是添加了一些代码来简化Washer的接口,以前调用者对Washer的内部很了解,但现在它对Washer几乎一无所知(除构造方法外)

3.适用于含有多个不同对象的子系统

例子中的Washer只是一个单一对象,好像应该由Washer本身提供这样的简单接口

但如果要实现日常起居的半自动化,我们会面对多个对象,比如门,窗,窗帘,电视,微波炉,洗衣机,电脑等等

我们希望一键准备早餐(自动开灯,自动开启微波炉加热),一键午睡(自动关门,自动拉上窗帘,自动熄灭灯光)等等功能,外观模式同样适用:

我们只需要让外观多持有几个具体对象就好了

4.有效地简化了子系统的接口

之前洗衣服需要蹲在洗衣机旁不停的操作,现在我们可以“一键完成”了,这才是我们想要的简单易用的接口

5.满足“最少知识原则”

我们做到了“只和朋友交谈”,我们的新系统只认识Facade,只和它交谈,而不是跑去和子系统中的一大堆低层组件交谈

四.总结

外观模式,用来为复杂的子系统提供简单易用的高层接口。

当你纠结于很多低层组件得不到解脱的时候,不妨去做一个遥控器,我想,你可能确实需要它。。

时间: 2025-01-11 01:05:51

设计模式之外观模式(Facade Pattern)的相关文章

二十四种设计模式:外观模式(Facade Pattern)

外观模式(Facade Pattern) 介绍为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 示例有一个Message实体类,某对象对它的操作有Get()方法,另外还有一个对象有一个Validate()方法来判断用户是否有权限.现在提供一个高层接口来封装这两个方法. MessageModel using System; using System.Collections.Generic; using System.Text; nam

设计模式-10外观模式(Facade Pattern)

1.模式动机 在现实生活中,常常存在办事较复杂的例子,如办房产证或注册一家公司,有时要同多个部门联系,这时要是有一个综合部门能解决一切手续问题就好了. 软件设计也是这样,当一个系统的功能越来越强,子系统会越来越多,客户对系统的访问也变得越来越复杂.这时如果系统内部发生改变,客户端也要跟着改变,这违背了"开闭原则",也违背了"迪米特法则(最少知道原则)",所以有必要为多个子系统提供一个统一的接口,从而降低系统的耦合度,这就是外观模式的目标. 2.模式定义 外观模式(F

设计模式 - 外观模式(facade pattern) 详解

外观模式(facade pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy 外观模式(facade pattern): 提供了一个统一的接口, 用来访问子系统中的一群接口. 外观定义了一个高层接口, 让子系统更容易使用. 外观模式包含三个部分: 1. 子系统: 子类, 单个复杂子类 或 多个子类; 2. 外观(facade)类: 把子系统设计的更加容易使用; 3. 客户: 只需要调用外观类. 与适配器模式(adapter pattern)的

设计模式之外观模式(Facade)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

设计模式之门面模式---Facade Pattern

模式的定义 门面模式(Facade Pattern)也叫做外观模式,定义如下: Provide a unified interface to a set of interfaces in a subsystem. Facade defines a highet-level interface that makes the subsystem easier to use. 要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行.门面模式提供一个高层次的接口,使得子系统更易于使用. 类型 结构

设计模式(结构型)之外观模式(Facade Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(结构型)之装饰者模式(Decorator Pattern)>http://blog.csdn.net/yanbober/article/details/45395747 概述 一个客户类需要和多个业务类交互,而这些业务类经常会作为整体出现,由于涉及到的类比较多,导致使

Java 设计模式:外观模式Facade

Facade 外观模式 外观模式----为子系统的一组接口提供一个统一的界面,此模式定义了一个更高层的接口,这一接口使得子系统更容易使用. 借用<大话设计模式>中的例子:市场上有N多只股票,当股民想要买股票时为了最大化自己的收益需要考察市面上很多种类的股票,然后根据自己的判断选取几只股票组合购买(这种场景下每一只股票都是可以单独购买的,用户需要考察.选取一组股票来一起购买).而有的用户直接购买基金,基金的作用是帮用户选取几只股票来组合购买,用户不用自己去选取多只股票. 在这个场景下:单独的购买

设计模式 笔记 外观模式 Facade

//---------------------------15/04/16---------------------------- //Facade 外观模式-----对象结构型模式 /* 1:意图: 为子系统的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得 这一子系统更加容易使用. 2:动机: 3:适用性: 1>当你要为一个复杂子系统提供一个简单接口时. 子系统往往因为不断演化而变得越来越复杂.大多数模式使用时都会产生更多更小的类. 这使得子系统更具可重用性,也更

11.外观模式(Facade Pattern)

using System; namespace ConsoleApplication4 { class Program { /// <summary> /// 不使用外观模式的情况 /// 此时客户端与三个子系统都发送了耦合,使得客户端程序依赖与子系统 /// 为了解决这样的问题,我们可以使用外观模式来为所有子系统设计一个统一的接口 /// 客户端只需要调用外观类中的方法就可以了,简化了客户端的操作 /// 从而让客户和子系统之间避免了紧耦合 /// </summary> ///

【设计模式】—— 外观模式Facade

前言:[模式总览]——————————by xingoo 模式意图 外观模式主要是为了为一组接口提供一个一致的界面.从而使得复杂的子系统与用户端分离解耦. 有点类似家庭常用的一键开关,只要按一个键,台灯卧室客厅的灯都亮了.虽然他们各有各自的开关,但是对外用一个来控制. 应用场景 1 为复杂系统 提供简单的接口. 2 客户程序与抽象类的实现部分分离. 3 构建层次系统时,用作入口. 模式结构 Facade 对外的统一接口 class Facade{ public void operation(){