一、描述
有很多子系統模塊,不想讓客戶端直接去訪問它們,定義一個外觀類,通過訪問這個外觀類類調用子系統模塊的功能。
二、優劣勢
優點:降低訪問複雜系統的內部子系統時的複雜度,簡化客戶端與之的接口。減少系統相互依賴、提高靈活性。 提高了安全性。
缺點:違背了“開閉原則”,當增加新的子系統或者移除子系統時需要修改外觀類。
三、需求
博物館監控系統,2個攝像頭,2個燈泡,1個警報器,每次開館和閉館時都要控制它們狀態。
四、不使用設計模式
都不考慮設計了,直接擼代碼。
3個類,
SheXiangTou.cs -攝像頭類
DengPao.cs -燈泡類
JingBaoQi.cs -警報器類
//攝像頭
public class SheXiangTou
{
private string name;
public SheXiangTou(string s)
{
name = s;
}
public void Open()
{
Debug.Log("攝像頭-"+name + "開啓");
}
public void Close()
{
Debug.Log("攝像頭-"+name + "關閉");
}
}
//燈泡
public class DengPao
{
private string name;
public DengPao(string s)
{
name = s;
}
public void Open()
{
Debug.Log("燈泡-" + name + "開啓");
}
public void Close()
{
Debug.Log("燈泡-" + name + "關閉");
}
}
//警報器
public class JingBaoQi
{
private string name;
public JingBaoQi(string s)
{
name = s;
}
public void Open()
{
Debug.Log("警報器-" + name + "開啓");
}
public void Close()
{
Debug.Log("警報器-" + name + "關閉");
}
}
//客戶端調用
public static void main(string[] args)
{
SheXiangTou sheXiangTou1 = new SheXiangTou("高清");
SheXiangTou sheXiangTou2 = new SheXiangTou("超高清");
DengPao dengPao1 = new DengPao("強光");
DengPao dengPao2 = new DengPao("弱光");
JingBaoQi jingBaoQi = new JingBaoQi("防盜");
Debug.Log("開館了");
sheXiangTou1.Open();
sheXiangTou2.Open();
dengPao1.Open();
dengPao2.Open();
jingBaoQi.Open();
Debug.Log("---------分割線---------");
Debug.Log("8小時過去了");
Debug.Log("閉館了");
sheXiangTou1.Close();
sheXiangTou2.Close();
dengPao1.Close();
dengPao2.Close();
jingBaoQi.Close();
}
運行結果
小結:可以看到在客戶端調用時非常麻煩,得手動去生成,並且一個一個的調用open,特別繁瑣。
五、使用設計模式
通過添加一個外觀介,把子系統都放在裏面,並提供外部訪問接口(方法)去調用它們。
4個類,
SheXiangTou.cs -攝像頭類
DengPao.cs -燈泡類
JingBaoQi.cs -警報器類
MonitorFacade.cs -監控系統中介類
//攝像頭
public class SheXiangTou
{
private string name;
public SheXiangTou(string s)
{
name = s;
}
public void Open()
{
Debug.Log("攝像頭-"+name + "開啓");
}
public void Close()
{
Debug.Log("攝像頭-"+name + "關閉");
}
}
//燈泡
public class DengPao
{
private string name;
public DengPao(string s)
{
name = s;
}
public void Open()
{
Debug.Log("燈泡-" + name + "開啓");
}
public void Close()
{
Debug.Log("燈泡-" + name + "關閉");
}
}
//警報器
public class JingBaoQi
{
private string name;
public JingBaoQi(string s)
{
name = s;
}
public void Open()
{
Debug.Log("警報器-" + name + "開啓");
}
public void Close()
{
Debug.Log("警報器-" + name + "關閉");
}
}
//監控系統中介類
public class MonitorFacade
{
SheXiangTou sheXiangTou1;
SheXiangTou sheXiangTou2;
DengPao dengPao1;
DengPao dengPao2;
JingBaoQi jingBaoQi;
public void Init()
{
sheXiangTou1 = new SheXiangTou("高清");
sheXiangTou2 = new SheXiangTou("超高清");
dengPao1 = new DengPao("強光");
dengPao2 = new DengPao("弱光");
jingBaoQi = new JingBaoQi("防盜");
Debug.Log("監控系統初始化完畢");
}
public void Open()
{
sheXiangTou1.Open();
sheXiangTou2.Open();
dengPao1.Open();
dengPao2.Open();
jingBaoQi.Open();
}
public void Close()
{
sheXiangTou1.Close();
sheXiangTou2.Close();
dengPao1.Close();
dengPao2.Close();
jingBaoQi.Close();
}
}
//客戶端調用
public static void main(string[] args)
{
MonitorFacade monitorFacade = new MonitorFacade();
monitorFacade.Init();
Debug.Log("開館了");
monitorFacade.Open();
Debug.Log("---------分割線---------");
Debug.Log("8小時過去了");
Debug.Log("閉館了");
monitorFacade.Close();
}
運行結果
小結:我們通過新加一個監控類,然後在裏面進行統一的初始化,開關控制,這樣客戶端調用就方便了很多,只需要操作監控類就可以控制全部系統了,這裏的監控類就是我們的外觀模式。注意下監控類裏不只是只能有Open和Close方法,可根據具體需求去擴展,比如只打開攝像頭OpenSheXiangTou(),再把攝像頭的開啓調用寫裏面就好了。
六、設計圖
通過學習,我們瞭解到了外觀者模式的應用,我們把剛剛的實現方式畫出來。
七、進階講解
剛剛說了外觀模式的弊端在於違反了開閉原則,也就是說如果我們想要再加一個紅外線設備進來,那麼我們要修改的地方有:MonitorFacade新加一個紅外線變量,並且修改Init(),Open(),Close()裏的方法,都要加上紅外線的開關調用。爲了解決這種反覆修改的問題,我們把抽象出一個外觀類基類Facade.cs,並且添加可重載方法Init、Open、Close,我們剛剛那個MonitorFacade去繼承它,然後新的需求是增加一個紅外線,那麼我們就再創建一個NewMonitorFacade類也繼承Facade,把紅外線的也給它加進去,然後客戶端那邊聲明 Facade facade,看看實際需求是要Facade facade= new MonitorFacade(),還是Facade facade= new NewMonitorFacade(),然後再調用facade裏的方法就可以了,總結一句話就是我們需要額外添加一個監控場所佈置,設備數量和之前的不同,就創建一個新的監控外觀類就可以了,這樣就不需要去修改原來的,符合開閉原則。
八、總結
一語道破:原來保安需要去攝像頭、燈泡、警報器的位置裏一次開啓開關,跑來跑去累死了,引入我們的外觀模式,就好比給他配置了一個電腦,只需要用鼠標點一下一鍵開啓所有開關就可以了,舒舒服服的坐在辦公室裏遙控,也不需要去跟那些攝像頭燈泡等打交道了。
覺得有用就留下評論吧^-^