外观模式--在各种套餐中早就用到啦!

2022-05-16 13:55:46 浏览数 (2)

引子

小帅和女朋友小美打算十一假期出去旅游,旅游攻略当然是小帅来做啦,为了给小美一个美好的旅游体验,小帅提前一个月就开始准备了。

首先当然是先选目的地啦,然后就是订机票,定酒店,安排行程,还有要计划好去哪里吃饭,去看看饭店的评价怎么样,还有......

这么一套流程下来,小帅感到做详细的攻略真的好麻烦啊,不过,为了小美,小帅没有一丝抱怨。

自己包办

为了保证小美对旅行的满意度,小帅尽量把所有的事情都提前安排好了。

期待了好一阵子,小帅和小美的旅游终于开始啦,整个行程如下:

代码语言: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的模式定义子系统每层的入口,实现层与层之间的解耦。

外观模式的优点:

  • 对客户屏蔽子系统的实现细节,减少了客户处理的对象数量,使子系统使用起来更加方便,通过引入外观模式,客户代码将变得更简单,与之关联的对象也更少。
  • 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。

好了,你觉得生活中还有哪些地方用到了外观模式呢?欢迎留言告诉我哦。

0 人点赞