[設計模式]Facade外觀模式
問題
為了降低複雜性,常常將系統劃分為若干個子系統。但是如何做到各個系統之間的通訊和相互依賴關係達到最小呢?
Facade外觀模式
外觀模式:為子系統中的一組介面提供一個一致的介面,Facade模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。引入外觀角色之後,使用者只需要直接與外觀角色互動,使用者與子系統之間的複雜關係由外觀角色來實現,從而降低了系統的耦合度。
Facade模式在高層提供了一個統一的介面,解耦了系統。設計模式中還有另一種模式Mediator也和Facade有類似的地方。但是mediator主要目的是物件間的訪問的解耦(通訊時候的協議)。
小demo
facade.h
#pragma once #include <iostream> #include <string> using namespace std; class SubSysOne { public: void Method() { cout<<"方法一"<<endl; } }; class SubSysTwo { public: void Method() { cout<<"方法二"<<endl; } }; class SubSysThree { public: void Method() { cout<<"方法三"<<endl; } }; class Facade { private: SubSysOne* sub1; SubSysTwo* sub2; SubSysThree* sub3; public: Facade(void) { sub1=new SubSysOne(); sub2=new SubSysTwo(); sub3=new SubSysThree(); } ~Facade(void) { delete sub1; delete sub2; delete sub3; } void FacadeMethod() { sub1->Method(); sub2->Method(); sub3->Method(); } };
main.cpp
#include "Facade.h"
#include <stdlib.h>
void main()
{
Facade* test=new Facade();
test->FacadeMethod();
delete test;
system("pause");
}
模式優缺點
優點
- 鬆散耦合:外觀模式鬆散了客戶端與子系統的耦合關係,讓子系統內部的模組能更容易擴充套件和維護。
- 簡單易用:外觀模式讓子系統更加易用,客戶端不再需要了解子系統內部的實現,也不需要跟眾多子系統內部的模組進行互動,只需要跟外觀類互動就可以了。
- 更好的劃分訪問層次:通過合理使用Facade,可以幫助我們更好地劃分訪問的層次。有些方法是對系統外的,有些方法是系統內部使用的。把需要暴露給外部的功能集中到門面中,這樣既方便客戶端使用,也很好地隱藏了內部的細節。
缺點
- 不能很好地限制客戶使用子系統類,如果對客戶訪問子系統類做太多的限制則減少了可變性和靈活性
- 在不引入抽象外觀類的情況下,增加新的子系統可能需要修改外觀類或客戶端的原始碼,違背了“開閉原則”
使用場景
1、當要為一個複雜子系統提供一個簡單介面時可以使用外觀模式。
2、客戶程式與多個子系統之間存在很大的依賴性。引入外觀類將子系統與客戶以及其他子系統解耦,可以提高子系統的獨立性和可移植性
模式總結
1、外觀模式的主要優點就在於減少了客戶與子系統之間的關聯物件,使用客戶對子系統的使用變得簡單了,也實現了客戶與子系統之間的鬆耦合關係。它的缺點就在於違背了“開閉原則”。
2、如果需要實現一個外觀模式,需要將子系統組合進外觀中,然後將工作委託給子系統執行。
模式擴充套件
一個系統有多個外觀類:
在外觀模式中,通常只需要一個外觀類,並且此外觀類只有一個例項,換言之它是一個單例類。在很多情況下為了節約系統資源,一般將外觀類設計為單例類。當然這並不意味著在整個系統裡只能有一個外觀類,在一個系統中可以設計多個外觀類,每個外觀類都負責和一些特定的子系統互動,向用戶提供相應的業務功能。
不要試圖通過外觀類為子系統增加新行為:
不要通過繼承一個外觀類在子系統中加入新的行為,這種做法是錯誤的。外觀模式的用意是為子系統提供一個集中化和簡化的溝通渠道,而不是向子系統加入新的行為,新的行為的增加應該通過修改原有子系統類或增加新的子系統類來實現,不能通過外觀類來實現。
實際應用Demo
package com.tuxing.sdk.facade;//facade包
import android.content.Context;
import com.tuxing.sdk.db.helper.GlobalDbHelper;
import com.tuxing.sdk.db.helper.UserDbHelper;
import com.tuxing.sdk.event.LoginEvent;
import com.tuxing.sdk.http.HttpClient;
import com.tuxing.sdk.manager.*;
import com.tuxing.sdk.manager.SecurityManager;
import com.tuxing.sdk.manager.impl.*;
import com.tuxing.sdk.utils.Constants;
import com.tuxing.sdk.utils.LogUtils;
import de.greenrobot.event.EventBus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//facade包下的一個CoreService類
//主要實現了與伺服器端的通訊介面,所以在啟動的時候都給建立了,(沒有過多的資源(圖片、視訊、音訊)佔用記憶體)
public class CoreService {
private final static Logger logger = LoggerFactory.getLogger(CoreService.class);
private static CoreService instance = new CoreService();
private Context context;
private HttpClient httpClient = HttpClient.getInstance();
private ContactManager contactManager = ContactManagerImpl.getInstance();
private NoticeManager noticeManager = NoticeManagerImpl.getInstance();
private void CoreService(){
}
public static CoreService getInstance(){
return instance;
}
public void start(Context context, String version, String host, int port) {
LogUtils.configure();
logger.debug("CoreService creating...");
EventBus.getDefault().registerSticky(this, Constants.EVENT_PRIORITY_SERVICE);
this.context = context;
GlobalDbHelper.getInstance().init(this.context);
httpClient.init(this.context, version);
httpClient.setHostAddress(host, port);
initComponents(version);
}
public void onEvent(LoginEvent event){
switch (event.getEvent()){
case LOGIN_SUCCESS:
UserDbHelper.getInstance().init(this.context, event.getUser().getUserId());
}
}
//統一初始化
public void initComponents(String version) {
logger.debug("CoreService starting...");
contactManager.init(this.context);
noticeManager.init(this.context);
//新增其他的Manager
}
//統一銷燬
public void stop(){
logger.debug("CoreService destroy...");
httpClient.onDestroy();
contactManager.destroy();
noticeManager.destroy();
//新增其他的Manager
}
//向外界提供統一的getX()介面
//CoreService.getInstance().getContactManager();
public ContactManager getContactManager() {
return contactManager;
}
public NoticeManager getNoticeManager() {
return noticeManager;
}
}