设计模式学习笔记--外观模式

Posted puppet_master

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式学习笔记--外观模式相关的知识,希望对你有一定的参考价值。

好久没写设计模式的blog了,这次重新回来填坑,先找一个最简单但是却最常用的设计模式来学习,外观模式。其实说是一个设计模式,其实我们在实际的编程中无时无刻不在用外观模式,可以说这个设计模式已经渗透到编程的各个方便,可能我们自己没感觉出来罢了。


一.外观模式的定义

先来看一下外观模式的定义:
外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层的接口,这个接口使得这一系列子系统更加容易使用。
简单解释一下,所谓外观模式,就是在我们设计系统的时候,将若干个子系统的功能整合到一个外观类中,通过这个外观类来调用子系统的功能,这样我们就可以简化客户端的调用,更重要的是可以将客户端和子系统解耦,当有子系统变化时,客户端不需要进行相应变动,只需要更改外观类即可。
下面是外观模式的UML图:
技术分享
如果没有Facade类,那么Client就需要分别和ClassA,ClassB,ClassC建立联系,那样的话,UML图就没有现在看起来这么简单明了了,有了外观模式,Client就可以直接调用Facade类,而完全不用管ClassA,ClassB,ClassC里面是什么东东。


二.外观模式的例子


我们通过一个例子来学习一下外观模式,看一下有外观模式和没有外观模式有什么区别。正好快要毕业了,准备粗去旅游一趟,然而身为一个宅到没朋友的阿猿,怎么安排出行就成了关键的问题,我选择了两种方式安排我的行程:

1.不使用外观模式

既然要出去玩,肯定要完成订灰机票,订酒店,买门票...等等一系列的准备工作,看下面的一段代码:
// Design Pattern.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
using namespace std;


//灰机公司
class AirlineCompany
{
private:
	//是否有票
	bool data[4];
public:
	AirlineCompany()
	{
		data[0] = false;
		data[1] = false;
		data[2] = true;
		data[3] = true;
	}

	void HasTicket(int day)
	{
		if (data[day])
			cout << day << " 日有灰机票!" << endl;
		else
			cout << day << " 日木有灰机票了!" << endl;
	}

	void BookTicket(int day)
	{
		cout << "你订了灰机票" << endl;
	}

	void PayForTicket()
	{
		cout << "你付了机票钱" << endl;
	}
};


//酒店类
class Hotel
{
private:
	//是否有空房间
	bool data[4];
public:
	Hotel()
	{
		data[0] = true;
		data[1] = false;
		data[2] = false;
		data[3] = true;
	}

	void HasTicket(int day)
	{
		if (data[day])
			cout << day << " 日有空房间!" << endl;
		else
			cout << day << " 日木有空房间了!" << endl;
	}

	void BookTicket(int day)
	{
		cout << "你预定了房间" << endl;
	}

	void PayForTicket()
	{
		cout << "你交了酒店订金" << endl;
	}
};


//景点类
class TouristSights
{
private:
	//ticket
	int data[4];
public:
	TouristSights()
	{
		data[0] = false;
		data[1] = true;
		data[2] = false;
		data[3] = true;
	}

	void HasTicket(int day)
	{
		if (data[day])
			cout << day << " 日可以参观!" << endl;
		else
			cout << day << " 日我们要闭馆!" << endl;
	}

	void BookTicket(int day)
	{
		cout << "你预定了门票" << endl;
	}

	void PayForTicket()
	{
		cout << "你付了门票钱" << endl;
	}
};


int _tmain(int argc, _TCHAR* argv[])
{
	//航空公司
	AirlineCompany* airlineCompany = new AirlineCompany();
	//酒店
	Hotel* hotel = new Hotel();
	//景点
	TouristSights* touristSight = new TouristSights();

	//恩,我先查看一下0日有木有各种票
	airlineCompany->HasTicket(0);
	hotel->HasTicket(0);
	touristSight->HasTicket(0);

	//....此处省略若干行,我终于找到3号各个地方都有票
	airlineCompany->HasTicket(3);
	hotel->HasTicket(3);
	touristSight->HasTicket(3);

	//我要开始订票了
	airlineCompany->BookTicket(3);
	hotel->BookTicket(3);
	touristSight->BookTicket(3);

	//我要付款了
	airlineCompany->PayForTicket();
	hotel->PayForTicket();
	touristSight->PayForTicket();

	//终于完事了,累死我了...
	cout << endl << "心好累,还是宅着好" << endl;
	system("pause");
	

	return 0;
}
结果如下:
0 日木有灰机票了!
0 日有空房间!
0 日我们要闭馆!
3 日有灰机票!
3 日有空房间!
3 日可以参观!
你订了灰机票
你预定了房间
你预定了门票
你付了机票钱
你交了酒店订金
你付了门票钱

心好累,还是宅着好

这个例子中,我们需要订机票,订酒店,订门票...而且每一个步骤都需要我们亲自参与,比如需要查询哪一天有机票,有酒店,需要查询三项同时合适的时间,然后才能订票,如果哪个阶段出了问题,就都需要全部重新搞,简直太麻烦了!

2.使用外观模式


自己订所有的东西实在是太难了,所以,就想到了某程网和去某网,于是就有了下面的一个例子:
// Design Pattern.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
using namespace std;


//灰机公司
class AirlineCompany
{
private:
	//是否有票
	bool data[4];
public:
	AirlineCompany()
	{
		data[0] = false;
		data[1] = false;
		data[2] = true;
		data[3] = true;
	}

	void HasTicket(int day)
	{
		
	}

	void BookTicket(int day)
	{
		
	}

	void PayForTicket()
	{
		
	}
};


//酒店类
class Hotel
{
private:
	//是否有空房间
	bool data[4];
public:
	Hotel()
	{
		data[0] = true;
		data[1] = false;
		data[2] = false;
		data[3] = true;
	}

	void HasTicket(int day)
	{

	}

	void BookTicket(int day)
	{
	
	}

	void PayForTicket()
	{
		
	}
};


//景点类
class TouristSights
{
private:
	//ticket
	int data[4];
public:
	TouristSights()
	{
		data[0] = false;
		data[1] = true;
		data[2] = false;
		data[3] = true;
	}

	void HasTicket(int day)
	{
		
	}

	void BookTicket(int day)
	{
		
	}

	void PayForTicket()
	{
		
	}
};


//旅游公司
class TravelCompany
{
private:
	AirlineCompany* m_AirlineCompany;
	Hotel*	        m_Hotel;
	TouristSights*  m_TouristSights;
public:
	TravelCompany()
	{
		m_AirlineCompany = new AirlineCompany();
		m_Hotel = new Hotel();
		m_TouristSights = new TouristSights();
	}

	void CheckSuitableDay()
	{
		//恩,旅游公司帮你查,怎么累都跟我们木有半毛钱关系
		m_AirlineCompany->HasTicket(0);
		m_Hotel->HasTicket(0);
		m_TouristSights->HasTicket(0);

		//....此处省略若干行,
		m_AirlineCompany->HasTicket(3);
		m_Hotel->HasTicket(3);
		m_TouristSights->HasTicket(3);

		cout << "找到了合适的行程" << endl;
	}

	void BookTravelPackage()
	{
		//帮你搞定一切
		m_AirlineCompany->BookTicket(3);
		m_Hotel->BookTicket(3);
		m_TouristSights->BookTicket(3);

		cout << "您已经预定好了行程" << endl;
	}

	void PayForPackage()
	{
		//一站式服务,包您满意
		m_AirlineCompany->PayForTicket();
		m_Hotel->PayForTicket();
		m_TouristSights->PayForTicket();

		cout << "付款完成!" << endl;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	TravelCompany* travelCompany = new TravelCompany();
	travelCompany->CheckSuitableDay();
	travelCompany->BookTravelPackage();
	travelCompany->PayForPackage();
	
	cout << endl << "轻松加愉快,外观模式万岁!" << endl;
	system("pause");
	

	return 0;
}
结果:
找到了合适的行程
您已经预定好了行程
付款完成!

轻松加愉快,外观模式万岁!

我们通过旅游公司,直接预订了一个套餐,包含了机票,酒店和门票,而这些都是旅游公司为我们安排好的,我们不需要直接和航空公司,酒店,景点直接打交道,也就没有了第一次那样N次查询结果与反馈,每一个步骤的预订,每个步骤的付款。我们只需要通过旅游公司一个接口,轻松搞定一切。

在这个例子中,子系统就相当于航空公司,酒店,景点,旅游公司就是外观类,而我们是客户端。如果没有旅游公司,那么我们就要分别和三个子系统打交道,而且是很多次复杂的耦合调用。而如果我们通过旅游公司,我们只需要和旅游公司自己打交道就可以了,在上面查询行程,预订,付款,一切就都OK了,当然,黑导游不在我们的考虑范围内。


三.外观模式总结


通过上面的例子,我们可以看出,有了外观模式,我们在客户端调用的时候会非常方便简洁,而且客户端没有和子系统发生耦合,但是外观模式并没有为系统增加任何新功能,换句话说,我们直接从客户端调用子系统和通过外观类调用子系统的效果是一样的,只是通过外观类比较方便。
总结一下外观模式的优缺点。

优点:
1)外观模式隐藏了子系统,通过更加简洁的接口和客户端交互,方便调用。
2)外观模式将客户端与子系统解耦,使子系统的变化不会影响客户端。
缺点:
1)不能够限制客户端直接调用子系统的代码,客户端可以选择直接调用子系统(不过我认为这也不一定就是缺点)。
2)没有增加新的功能,但是如过增加子系统,设计不当的情况下可能会要额外修改外观类,不符合开放封闭原则。

好了,关于外观模式就说这些了。其实外观模式只要是面向对象编程的筒子们应该都用过千万次了,对象之间的组合关系其实就是外观模式的体现。当我们设计好一些子系统时,给这些子系统设计一个包装类,提供一套方便的接口,然后这些包装类再合成更加高层的接口,就逐步实现了层次的结构。

.
































以上是关于设计模式学习笔记--外观模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式:学习笔记(11)——外观模式

《设计模式》学习笔记8——外观模式

外观模式——HeadFirst设计模式学习笔记

《Android源代码设计模式解析与实战》读书笔记(二十三)

学习设计模式之外观模式

swift设计模式学习 - 外观模式