Java進階篇設計模式之十 ---- 訪問者模式和中介者模式
前言
在上一篇中我們學習了結構型模式的直譯器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern)。本篇則來學習下行為型模式的兩個模式,訪問者模式(Visitor Pattern)和中介者模式(Mediator Pattern)。
訪問者模式
簡介
訪問者模式(VisitorPattern),顧名思義使用了這個模式後就可以在不修改已有程式結構的前提下,通過新增額外的訪問者來完成對已有程式碼功能的提升,它屬於行為模式。訪問者模式的目的是封裝一些施加於某種資料結構元素之上的操作。一旦這些操作需要修改的話,接受這個操作的資料結構則可以保持不變。 其主要目的是將資料結構與資料操作分離。
訪問者模式可以說是設計模式中最難以理解的一個模式,因為相比其它模式而言,它過於”繞“了。但是我們可以通過生活中的一些例子來理解它,比如家裡來了客人,客人就是訪問者,他可以做一些事情,但是又不能做全部的事情; 又或者說去網咖上網的小明,小明也是訪問者,他可以在網咖玩遊戲、看視訊、聽音樂等等,但是不能破壞網咖中的裝置等等。按照這麼理解,我們大概就可以知道訪問者模式主要是做什麼了。
訪問者模式主要由這五個角色組成,抽象訪問者(Visitor)、具體訪問者(ConcreteVisitor)、抽象節點(Node)、具體節點(ConcreteNode)和結構物件(ObjectStructure)。
- 抽象訪問者(Visitor)角色:聲明瞭一個或者多個方法操作,形成所有的具體訪問者角色必須實現的介面。
- 具體訪問者(ConcreteVisitor)角色:實現抽象訪問者所宣告的介面,也就是抽象訪問者所宣告的各個訪問操作。
- 抽象節點(Node)角色:宣告一個接受操作,接受一個訪問者物件作為一個引數。
- 具體節點(ConcreteNode)角色:實現了抽象節點所規定的接受操作。
- 結構物件(ObjectStructure)角色:有如下的責任,可以遍歷結構中的所有元素。
示例圖如下:
這裡為了方便理解,我們使用一個簡單的示例來加以說明。 圖書館有一臺電腦,有兩個賬戶,其中一個是管理員的賬戶,擁有所有許可權,但是設定了密碼;另一個賬戶是不需要密碼,但是隻能玩遊戲和看圖片。張三和李四先後使用了這臺電腦,那麼他們就可以當作是訪問者。 那麼我們便可以根據這裡例子來使用訪問者模式進行開發,首先定義一個抽象的訪問者,擁有玩遊戲和看圖片的方法;然後再定義一個抽象節點電腦,接受這個請求。 那麼這個抽象類的程式碼如下:
interface Visitor {
void visit(Games games);
void visit(Photos photos);
}
interface Computer {
void accept(Visitor visitor);
}
複製程式碼
定義好該抽象類之後,我們需要設計不同的訪問者對節點進行不同的處理。並且需要設計具體節點類實現剛剛抽象節點的方法。
那麼程式碼如下:
class ZhangSan implements Visitor {
@Override
public void visit(Games games) {
games.play();
}
@Override
public void visit(Photos photos) {
photos.watch();
}
}
class LiSi implements Visitor {
@Override
public void visit(Games games) {
games.play();
}
@Override
public void visit(Photos photos) {
photos.watch();
}
}
class Games implements Computer {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void play() {
System.out.println("play lol");
}
}
class Photos implements Computer {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void watch() {
System.out.println("watch scenery photo");
}
}
複製程式碼
最後我們還需要定義一個結構物件角色,提供一個的介面並允許該訪問者進行訪問,它可以對這些角色進行增加、修改或刪除等操作和遍歷。 程式碼如下:
class ObjectStructure {
private List<Computer> computers = new ArrayList<Computer>();
public void action(Visitor visitor) {
computers.forEach(c -> {
c.accept(visitor);
});
}
public void add(Computer computer) {
computers.add(computer);
}
}
複製程式碼
編寫好之後,那麼我們來進行測試。 測試程式碼如下:
public static void main(String[] args) {
// 建立一個結構物件
ObjectStructure os = new ObjectStructure();
// 給結構增加一個節點
os.add(new Games());
// 給結構增加一個節點
os.add(new Photos());
// 建立一個訪問者
Visitor visitor = new ZhangSan();
os.action(visitor);
}
複製程式碼
輸出結果:
play lol
watch scenery photo
複製程式碼
訪問者模式優點:
擴充套件性好,可以在不修改物件結構中的元素的情況下,為物件結構中的元素新增新的功能; 符合單一職責原則,通過訪問者將無關的行為分離,使職責單一;
訪問者模式缺點:
違反了迪米特原則,因為具體元素對訪問者公佈細節; 違反了依賴倒置原則,依賴了具體類,沒有依賴抽象; 物件結構變化困難,若物件結構發生了改變,訪問者的介面和訪問者的實現也都要發生相應的改變;
使用場景:
物件結構中物件對應的類很少改變,但經常需要在此物件結構上定義新的操作; 需要對一個物件結構中的物件進行很多不同的並且不相關的操作,而需要避免讓這些操作"汙染"這些物件的類,也不希望在增加新操作時修改這些類。
中介者模式
簡介
中介者模式(Mediator Pattern),定義了一箇中介物件來封裝一系列物件之間的互動關係。中介者使各個物件之間不需要顯式地相互引用,從而使耦合性降低,而且可以獨立地改變它們之間的互動行為,屬於行為型模式。 其主要的目的是用來降低多個物件和類之間的通訊複雜性。
簡單的來說就是提供一個平臺。比如生活中我們經常用到的聊天軟體QQ、微信群,或者是上網購物的網站淘寶、京東,又或者是房產中介。但是無論是QQ群,還是房產中介,他們都是充當一箇中間平臺的作用,我們可以直接通過這個平臺得到我們想要的資訊,避免了獨自獲取花費的成本。
中介者模式主要由這四個角色組成, 抽象中介者(Mediator)、具體中介者(ConcreteMediator)、 抽象同事類(Colleague)和具體同事類(ConcreteColleague) 。
- 抽象中介者(Mediator): 定義了同事物件到中介者物件之間的介面。
- 具體中介者(ConcreteMediator): 實現抽象中介者的方法,它需要知道所有的具體同事類,同時需要從具體的同事類那裡接收資訊,並且向具體的同事類傳送資訊。
- 抽象同事類(Colleague): 定義了中介者物件的介面,它只知道中介者而不知道其他的同事物件。
- 具體同事類(ConcreteColleague) : 每個具體同事類都只需要知道自己的行為即可,但是他們都需要認識中介者。
示例圖如下:
這裡為了方便理解,我們使用一個簡單的示例來加以說明。 xuwujing建立了一個Java的QQ群,並邀請了很多人進來,其中張三也加進來了,進群之後,大家開始互相打招呼進行交流。。。 那麼我們便可以根據這個簡單的例子來使用中介者模式進行開發。 首先依舊定義一個抽象的中介者,就是QQ群,可以進行交流;然後再定義一個抽象的同事類,可以談話。 那麼這個抽象類的程式碼如下:
interface QQqun {
void exchange(Person person,String message);
}
abstract class Person{
protected String name;
protected QQqun qun;
Person(String name,QQqun qun){
this.name = name;
this.qun = qun;
}
}
複製程式碼
定義好該抽象類之後,我們再來定義具體的同事類,也就是xuwujing和張三,可以進行交流。
那麼程式碼如下:
class ZhangSan extends Person{
ZhangSan(String name, QQqun qun) {
super(name, qun);
}
void exchange(String message){
qun.exchange(this,message);
}
void talk(String message){
System.out.println(name +"說:" + message);
}
}
class XuWuJing extends Person{
XuWuJing(String name, QQqun qun) {
super(name, qun);
}
void exchange(String message){
qun.exchange(this,message);
}
void talk(String message){
System.out.println(name +"迴應:" + message);
}
}
複製程式碼
最後再來定義具體中介者物件,這個QQ群的具體實現。 程式碼如下:
class JavaQQqun implements QQqun{
private ZhangSan zs;
private XuWuJing xwj;
public ZhangSan getZs() {
return zs;
}
public void setZs(ZhangSan zs) {
this.zs = zs;
}
public XuWuJing getXwj() {
return xwj;
}
public void setXwj(XuWuJing xwj) {
this.xwj = xwj;
}
@Override
public void exchange(Person person, String message) {
if(zs.equals(person)){
zs.talk(message);
}else if(xwj.equals(person)){
xwj.talk(message);
}
}
}
複製程式碼
最後再來進行測試,定義好交流平臺以及需要交流的人員。 那麼測試程式碼如下:
public static void main(String[] args) {
JavaQQqun jq = new JavaQQqun();
ZhangSan zs = new ZhangSan("張三", jq);
XuWuJing xwj = new XuWuJing("xuwujing", jq);
jq.setZs(zs);
jq.setXwj(xwj);
zs.talk("大家好!我是張三!");;
xwj.talk("歡迎你!張三!");
}
複製程式碼
輸出結果:
張三說:大家好!我是張三
xuwujing迴應:歡迎你!張三!
複製程式碼
中介者模式優點:
靈活性高,因為將同事類進行了解耦,使其不必有關聯性; 降低了類的複雜度,將一對多轉化成了一對一;
中介者模式缺點:
中介者使用過多,會使系統變得複雜難以維護;
使用場景:
通過一箇中間類來封裝多個類中的行為,而又不想生成太多的子類。
注意事項:
若不明確各個類的職責,那麼就不要進行使用!
和外觀模式、代理模式比較
中介者模式和外觀模式、代理模式比較類似,但是又有不同。 和外觀模式比較,中介者模式中,同事類必須依賴與中介者,中介者也知道同事類;但是外觀模式中,子系統是不需要知道外觀類的存在,並且子系統是可以脫離外觀模式的。 和代理模式,代理模式的核心就是代理作用,主要還是對原先的類進行擴充套件或增加控制,比如進行許可權控制;而中介者模式主要目的是為了減少物件之前的耦合,也就是同事類直接相互獨立,互不影響。
參考文章: www.cnblogs.com/chenssy/p/3…
其它
音樂推薦
分享一首很有節奏感的電音!
專案的程式碼
java-study 是本人在學習Java過程中記錄的一些程式碼,也包括之前博文中使用的程式碼。如果感覺不錯,希望順手給個start,當然如果有不足,也希望提出。 github地址: github.com/xuwujing/ja…
原創不易,如果感覺不錯,希望給個推薦!您的支援是我寫作的最大動力! 版權宣告: 作者:虛無境
部落格園出處:www.cnblogs.com/xuwujing CSDN出處:blog.csdn.net/qazwsxpcm 個人部落格出處:www.panchengming.com