引子
小帅和女朋友小美打算十一假期出去旅游,旅游攻略当然是小帅来做啦,为了给小美一个美好的旅游体验,小帅提前一个月就开始准备了。
首先当然是先选目的地啦,然后就是订机票,定酒店,安排行程,还有要计划好去哪里吃饭,去看看饭店的评价怎么样,还有......
这么一套流程下来,小帅感到做详细的攻略真的好麻烦啊,不过,为了小美,小帅没有一丝抱怨。
自己包办
为了保证小美对旅行的满意度,小帅尽量把所有的事情都提前安排好了。
期待了好一阵子,小帅和小美的旅游终于开始啦,整个行程如下:
代码语言:javascript复制/**
* 航空公司
*/
public class Airline {
public void economyClass() {
System.out.println("坐经济舱");
}
public void businessClass() {
System.out.println("坐商务舱");
}
}
代码语言:javascript复制/**
* 酒店
*/
public class Hotel {
public void homestay() {
System.out.println("住民宿");
}
public void threeStarHotel() {
System.out.println("住三星级酒店");
}
public void fourStarHotel() {
System.out.println("住四星级酒店");
}
public void fiveStarHotel() {
System.out.println("住五星级酒店");
}
}
代码语言:javascript复制/**
* 餐厅
*/
public class Restaurant {
public void foodStall() {
System.out.println("去大排档吃烧烤");
}
public void hotPot() {
System.out.println("去吃火锅");
}
public void westernRestaurant() {
System.out.println("去西餐厅烛光晚餐");
}
}
代码语言:javascript复制/**
* 景点
*/
public class Attraction {
public void museum() {
System.out.println("去博物馆");
}
public void aquarium() {
System.out.println("去水族馆");
}
public void scenicArea() {
System.out.println("去风景区");
}
public void skyscrapers() {
System.out.println("参观摩天大楼");
}
}
代码语言:javascript复制/**
* 自己旅游
*/
public class SelfTravel {
public static void main(String[] args) {
Airline airline = new Airline();
Hotel hotel = new Hotel();
Restaurant restaurant = new Restaurant();
Attraction attraction = new Attraction();
// 坐经济舱
airline.economyClass();
// 住民宿
hotel.homestay();
// 吃大排档
restaurant.foodStall();
// 去博物馆玩
attraction.museum();
// 去水族馆
attraction.aquarium();
// 去风景区玩
attraction.scenicArea();
}
}
输出:
代码语言:javascript复制坐经济舱
住民宿
去大排档吃烧烤
去博物馆
去水族馆
去风景区
旅行回来后,小帅发现小美好像有点不高兴,尽管小美嘴上没这么说,但是可以看出来,小美对这次旅程并不满意。
旅行社
转眼到了第二年,小美又提出来去旅游了,小帅想起去年旅游的经历,发现自己安排行程真是吃力不讨好,这次小帅决定找个旅行社定个套餐,一下子就能搞定。
代码语言:javascript复制/**
* 旅行社
*/
public class TravelAgency {
Airline airline = new Airline();
Hotel hotel = new Hotel();
Restaurant restaurant = new Restaurant();
Attraction attraction = new Attraction();
/**
* 低端套餐
*/
public void lowEndPackage() {
System.out.println("低端套餐:");
// 坐经济舱
airline.economyClass();
// 住民宿
hotel.homestay();
// 吃大排档
restaurant.foodStall();
// 去水族馆
attraction.aquarium();
// 去风景区
attraction.scenicArea();
}
/**
* 中端套餐
*/
public void midRangePackage() {
System.out.println("中端套餐:");
// 坐经济舱
airline.economyClass();
// 住四星级酒店
hotel.fourStarHotel();
// 吃火锅
restaurant.hotPot();
// 去博物馆
attraction.museum();
// 去水族馆
attraction.aquarium();
// 去风景区
attraction.scenicArea();
}
/**
* 高端套餐
*/
public void highEndPackage() {
System.out.println("高端套餐:");
// 坐商务舱
airline.businessClass();
// 住五星级酒店
hotel.fiveStarHotel();
// 吃西餐厅
restaurant.westernRestaurant();
// 去博物馆
attraction.museum();
// 去水族馆
attraction.aquarium();
// 去风景区
attraction.scenicArea();
// 参观摩天大楼
attraction.skyscrapers();
}
}
旅行社一共有低端,中端,高端三种套餐,小帅选了高级套餐:
代码语言:javascript复制/**
* 跟团旅游
*/
public class GroupTravel {
public static void main(String[] args) {
TravelAgency travelAgency = new TravelAgency();
// 高端套餐
travelAgency.highEndPackage();
}
}
代码语言:javascript复制高端套餐:
坐商务舱
住五星级酒店
去西餐厅烛光晚餐
去博物馆
去水族馆
去风景区
参观摩天大楼
这次小美旅游回来,脸上笑开了花,小帅心中暗喜,这钱花的值啊。
外观模式
不知道不觉中,我们已经使用了外观模式,是不是很简单?下面我们来看看外观模式的定义吧。
外观模式(Facade Pattern):外观模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。外观模式又称为门面模式,它是一种对象结构型模式。
(图片来源:https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/facade.html)
外观模式的重点是定义一组高层接口让子系统更易用。
使用外观模式之前:
使用外观模式之后:
回到上面的例子,小帅如果自己规划旅游行程的话,需要自己去订机票,订酒店,定餐厅等等,需要和很多子系统打交道,这样会变的很繁琐。
后来小帅找了旅行社,直接选择了一种套餐,这里的旅行社就是一种外观模式,套餐里包含了机票,酒店,餐厅,门票等等,让旅行社和各个子系统打交道,小帅只要选择一种套餐(外观)就行了,让选择更简单。
当然,旅行社可以提供多种套餐(外观)供客户(系统)选择(调用),比如小帅为了省钱可以选择低端套餐:
代码语言:javascript复制/**
* 跟团旅游
*/
public class GroupTravel {
public static void main(String[] args) {
TravelAgency travelAgency = new TravelAgency();
// 低端套餐
travelAgency.lowEndPackage();
}
}
代码语言:javascript复制低端套餐:
坐经济舱
住民宿
去大排档吃烧烤
去水族馆
去风景区
恩,小帅已经感受到小美的怒火了,赶紧改回了高端套餐保命。
总结
外观模式符合迪米特法则(Law of Demeter)又叫作最少知识原则(The Least Knowledge Principle):一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,两个有交互的系统,只暴露有限的必要的接口,也就是说:只和你的密友交谈。
适合使用外观模式的情景:
- 当你要为一个复杂的子系统提供一个简单接口的时候。
- 客户程序与子系统之间存在着很大的依赖性,需要解耦的时候。
- 需要构建一个多层次的系统的时候,可以使用Face的模式定义子系统每层的入口,实现层与层之间的解耦。
外观模式的优点:
- 对客户屏蔽子系统的实现细节,减少了客户处理的对象数量,使子系统使用起来更加方便,通过引入外观模式,客户代码将变得更简单,与之关联的对象也更少。
- 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。
好了,你觉得生活中还有哪些地方用到了外观模式呢?欢迎留言告诉我哦。