設(shè)計(jì)模式系列—外觀模式
前言
- 23種設(shè)計(jì)模式速記
- 單例(singleton)模式
- 工廠方法(factory method)模式
- 抽象工廠(abstract factory)模式
- 建造者/構(gòu)建器(builder)模式
- 原型(prototype)模式
- 享元(flyweight)模式
- 持續(xù)更新中......
23種設(shè)計(jì)模式快速記憶的請(qǐng)看上面第一篇,本篇和大家一起來(lái)學(xué)習(xí)外觀(門面)模式相關(guān)內(nèi)容,外觀模式一定是我們平常使用最多的一種。
總體概覽
模式定義
為子系統(tǒng)中的一組接口提供一個(gè)一致的接口,F(xiàn)acade 模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。
通過(guò)創(chuàng)建一個(gè)統(tǒng)一的外觀類,用來(lái)包裝子系統(tǒng)中一個(gè) / 多個(gè)復(fù)雜的類,客戶端可通過(guò)調(diào)用外觀類的方法來(lái)調(diào)用內(nèi)部子系統(tǒng)中所有方法。
解決的問(wèn)題
- 避免了系統(tǒng)與系統(tǒng)之間的高耦合度
- 使得復(fù)雜的子系統(tǒng)用法變得簡(jiǎn)單
實(shí)例說(shuō)明
步驟1:定義subsystem角色
- class SubSystemOne {
- public void methodOne() {
- System.out.println("子系統(tǒng)方法一");
- }
- }
- class SubSystemTwo {
- public void methodTwo() {
- System.out.println("子系統(tǒng)方法二");
- }
- }
- class SubSystemThree {
- public void methodThree() {
- System.out.println("子系統(tǒng)方法三");
- }
- }
- class SubSystemFour {
- public void methodFour() {
- System.out.println("子系統(tǒng)方法四");
- }
- }
步驟2:定義Facade角色
- class Facade {
- SubSystemOne one;
- SubSystemTwo two;
- SubSystemThree three;
- SubSystemFour four;
- public Facade() {
- this.one = new SubSystemOne();
- this.two = new SubSystemTwo();
- this.three = new SubSystemThree();
- this.four = new SubSystemFour();
- }
- public void MethodA() {
- System.out.println("方法組A()----");
- one.methodOne();
- two.methodTwo();
- four.methodFour();
- }
- public void MethodB() {
- System.out.println("方法組B()----");
- two.methodTwo();
- three.methodThree();
- }
- }
步驟3:驗(yàn)證輸出結(jié)果
- /**
- * 外觀/門面模式
- */
- public class FacadePattern {
- public static void main(String[] args) {
- Facade facade = new Facade();
- facade.MethodA();
- facade.MethodB();
- System.out.println("----over----");
- }
- }
輸出如下:
- 方法組A()----
- 子系統(tǒng)方法一
- 子系統(tǒng)方法二
- 子系統(tǒng)方法四
- 方法組B()----
- 子系統(tǒng)方法二
- 子系統(tǒng)方法三
- ----over----
優(yōu)點(diǎn)
- 減少系統(tǒng)的相互依賴;
- 外觀模式通過(guò)封裝子系統(tǒng),向上層模塊提供統(tǒng)一的接口,從而降低的上層模塊與子系統(tǒng)的過(guò)度耦合;
- 提高了靈活性;
- 提高安全性。
缺點(diǎn)
不符合開(kāi)閉原則:在不對(duì)外觀類進(jìn)行抽象的時(shí)候,如果需要添加新的子系統(tǒng),就需要對(duì)Facade類進(jìn)行修改。
應(yīng)用場(chǎng)景
- 要為一個(gè)復(fù)雜的子系統(tǒng)對(duì)外提供一個(gè)簡(jiǎn)單的接口
- 提供子系統(tǒng)的獨(dú)立性
- 客戶程序與多個(gè)子系統(tǒng)之間存在很大的依賴性
引入外觀類將子系統(tǒng)與客戶以及其他子系統(tǒng)解耦,可以提高子系統(tǒng)的獨(dú)立性和可移植性。
- 在層次化結(jié)構(gòu)中,可以使用外觀模式定義系統(tǒng)中每一層的入口
層與層之間不直接產(chǎn)生聯(lián)系,而通過(guò)外觀類建立聯(lián)系,降低層之間的耦合度。
與適配器模式的區(qū)別
外觀模式的實(shí)現(xiàn)核心主要是:由外觀類去保存各個(gè)子系統(tǒng)的引用,實(shí)現(xiàn)由一個(gè)統(tǒng)一的外觀類去包裝多個(gè)子系統(tǒng)類,然而客戶端只需要引用這個(gè)外觀類,然后由外觀類來(lái)調(diào)用各個(gè)子系統(tǒng)中的方法。
這樣的實(shí)現(xiàn)方式非常類似適配器模式,然而外觀模式與適配器模式不同的是:適配器模式是將一個(gè)對(duì)象包裝起來(lái)以改變其接口,而外觀是將一群對(duì)象 ”包裝“起來(lái)以簡(jiǎn)化其接口。它們的意圖是不一樣的,適配器是將接口轉(zhuǎn)換為不同接口,而外觀模式是提供一個(gè)統(tǒng)一的接口來(lái)簡(jiǎn)化接口。
源碼中的應(yīng)用
- #tomcat
- org.apache.catalina.connector.RequestFacade
- org.apache.catalina.connector.ResponseFacade
- #mybatis
- Configuration
- ......
RequestFacade源碼分析
Tomcat中門面模式使用的很多,因?yàn)門omcat中有很多不同組件,每個(gè)組件要相互通信,但是又不能將自己的內(nèi)部數(shù)據(jù)過(guò)多的暴露給其他組件。用門面模式隔離數(shù)據(jù)是很好的方法。
Tomcat 中 Request 除了實(shí)現(xiàn)了 ServletRequest 接口外,還會(huì)有額外的一些函數(shù),而這些函數(shù)需要被其他類調(diào)用,但這些方法不應(yīng)該暴露給上層,因?yàn)樯蠈討?yīng)該專注于 ServletRequest 的實(shí)現(xiàn)。于是在 Tomcat 中會(huì)使用 Facade 模式了。
未使用 Facade 模式前如下:
未使用 Facade 模式前的 process 處理請(qǐng)求是這樣的
- public class ServletProcess {
- public void process(Request request, Response response){
- //....
- servlet = (Servlet) myClass.newInstance();
- servlet.service((ServletRequest) request, (ServletResponse) response);
- }
- }
而使用 Facade 模式之后如下:
而使用 Facade 后的 process 處理請(qǐng)求是這樣的
- public class ServletProcess {
- public void process(Request request, Response response){
- //....
- RequestFacade requestFacade = new RequestFacade(request);
- ResponseFacade responseFacade = new ResponseFacade(response);
- servlet = (Servlet) myClass.newInstance();
- servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade);
- }
- }
為了達(dá)到這種效果,RequestFacade 使用了類似代理模式的實(shí)現(xiàn)方式。
- public class RequestFacade implements HttpServletRequest {
- private ServletRequest request;
- public RequestFacade(ServletRequest request) {
- this.request = request;
- }
- @Override
- public String getAuthType() {
- return request.getAuthType();
- }
- }
對(duì)象里有個(gè) ServletRequest 對(duì)象,而 RequestFacade 的所有方法都會(huì)委托給 ServletRequest 調(diào)用。
Configuration源碼分析
由上面的類圖可以看出,client只需要調(diào)用Configuration的newMetaObject(Object object)方法就可以得到一個(gè)MetaObject對(duì)象,而具體的對(duì)象是怎么生成與client無(wú)關(guān),下面我們可以看一下Configuration的部分源碼分析。
Configuration部分源碼
- //Configuration 類:
- public class Configuration {
- protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
- protected ObjectFactory objectFactory = new DefaultObjectFactory();
- protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
- public MetaObject newMetaObject(Object object) {
- return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
- }
- }
- //MetaObject類
- public class MetaObject {
- private Object originalObject;
- private ObjectWrapper objectWrapper;
- private ObjectFactory objectFactory;
- private ObjectWrapperFactory objectWrapperFactory;
- private ReflectorFactory reflectorFactory;
- public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
- if (object == null) {
- return SystemMetaObject.NULL_META_OBJECT;
- } else {
- return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
- }
- }
- private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
- this.originalObject = object;
- this.objectFactory = objectFactory;
- this.objectWrapperFactory = objectWrapperFactory;
- this.reflectorFactory = reflectorFactory;
- if (object instanceof ObjectWrapper) {
- this.objectWrapper = (ObjectWrapper) object;
- } else if (objectWrapperFactory.hasWrapperFor(object)) {
- this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
- } else if (object instanceof Map) {
- this.objectWrapper = new MapWrapper(this, (Map) object);
- } else if (object instanceof Collection) {
- this.objectWrapper = new CollectionWrapper(this, (Collection) object);
- } else {
- this.objectWrapper = new BeanWrapper(this, object);
- }
- }
- }
由上面的部分源碼可以看出,客戶端只需要調(diào)用Configuration的newMetaObject(Object object)方法,并傳遞一個(gè)Object參數(shù),就可以獲取對(duì)應(yīng)的MetaObject,至于具體的產(chǎn)生什么樣的MetaObject,則有MetaObject的類的forObject(object, objectFactory, objectWrapperFactory, reflectorFactory)方法實(shí)現(xiàn)。
PS:以上代碼提交在 Github :
https://github.com/Niuh-Study/niuh-designpatterns.git