折騰Java設計模式之中介者模式
中介者模式(Mediator Pattern)是用來降低多個物件和類之間的通訊複雜性。這種模式提供了一箇中介類,該類通常處理不同類之間的通訊,並支援鬆耦合,使程式碼易於維護。中介者模式屬於行為型模式。
通俗點來講就是提供一箇中介平臺,說到平臺,那其實很容易聯絡到我們很熟悉的房地產中介。我們可以直接通過這個平臺得到我們想要的資訊,不用物件自身與其他物件互動。
買房子租房子就不需要去找房東,只需要在中介那裡獲取相應的房產資訊。如下圖那樣,兩方只需要找中介即可。

再來看一張對比圖。

有沒有感覺沒有使用之前,物件間互相依賴互相呼叫,錯綜複雜,盤根錯節,當加入中介者後,物件間的關係一目瞭然,清晰明瞭。由中介物件來封裝一系列物件之間的互動關係。中介者使各個物件之間不需要顯式地相互引用,從而使耦合性降低,而且可以獨立地改變它們之間的互動行為。
中介者模式UML圖
UML類圖和時序圖

collague1和collague2類不直接相互依賴,它們是用起控制和協調互動作用的公共中介介面(mediate()方法),這使它們有獨立互動的執行方式。mediate1類實現collague1和collague2之間的依賴。
中介者模式角色

抽象中介者(Mediator): 定義了同事物件到中介者物件之間的介面。
具體中介者(ConcreteMediator): 實現抽象中介者的方法,它需要知道所有的具體同事類,同時需要從具體的同事類那裡接收資訊,並且向具體的同事類傳送資訊。
抽象同事類(Colleague): 定義了中介者物件的介面,它只知道中介者而不知道其他的同事物件。
具體同事類(ConcreteColleague) : 每個具體同事類都只需要知道自己的行為即可,但是他們都需要認識中介者。
示例程式碼
抽象中介者
@Slf4j public abstract class Mediator { /** * 房東map */ protected Map<People, Message> landlordMap = Maps.newHashMap(); /** * 租戶列表 */ protected List<People> renterList = Lists.newArrayList(); /** * 註冊房東資訊 * * @param landlord 房東 * @param message房屋資訊 */ public void registerLandlord(People landlord, Message message) { landlordMap.put(landlord, message); log.info("中介資訊:房東|{}|加入到中介平臺,房屋資訊:{}", landlord.getName(), message); } /** * 變更房東資訊 * * @param landlord 房東 * @param message房屋資訊 */ protected void modifyLandlordInfo(People landlord, Message message) { landlordMap.put(landlord, message); log.info("中介資訊:房東|{}|修改他在中介平臺的房屋資訊,現房屋資訊:{}", landlord.getName(), message); } /** * 註冊租戶資訊 * * @param renter 租戶 */ public void registerRenter(People renter) { renterList.add(renter); log.info("中介資訊:租戶|{}|來中介平臺租房", renter.getName()); } /** * 宣告抽象方法 由具體中介者子類實現 訊息的中轉和協調 */ public abstract void operation(People people, Message message); } 複製程式碼
抽象同事類
@Data @AllArgsConstructor @NoArgsConstructor public abstract class People { private Mediator mediator; private String name; /** * 向中介傳送訊息 */ protected abstract void sendMessage(Message message); /** * 從中介獲取訊息 */ protected abstract void getMessage(Message message); } 複製程式碼
具體同事類 房東和租戶
@Slf4j public class Landlord extends People { public Landlord(Mediator mediator, String name) { super(mediator, name); } @Override protected void sendMessage(Message message) { getMediator().operation(this, message); } @Override protected void getMessage(Message message) { log.info("房東|{}|從中介獲取到租戶的資訊:{}", getName(), message); } } 複製程式碼
@Slf4j public class Renter extends People { public Renter(Mediator mediator, String name) { super(mediator, name); } @Override protected void sendMessage(Message message) { getMediator().operation(this, message); } @Override protected void getMessage(Message message) { log.info("租戶|{}|從中介獲取到房東的資訊:{}", getName(), message); } } 複製程式碼
具體中介者
public class RealEstateAgent extends Mediator { @Override public void operation(People people, Message message) { if (people instanceof Renter) { // 將租戶的租房條件資訊傳送給房東們 landlordMap.keySet().forEach(landlord -> landlord.getMessage(message)); // 租戶收到中介那裡房東的房屋資訊 landlordMap.values().forEach(messages -> people.getMessage(messages)); } else if (people instanceof Landlord) { // 將房東的房屋資訊傳送給租戶們 renterList.forEach(renter -> renter.getMessage(message)); // 變更中介裡的房東房屋資訊 modifyLandlordInfo(people, message); } } } 複製程式碼
客戶端
@Slf4j public class Client { public static void main(String[] args) { Mediator mediator = new RealEstateAgent(); People laoWang = new Landlord(mediator, "老王"); People laoLee = new Landlord(mediator, "老李"); People laoBai = new Landlord(mediator, "老白"); People xiaoSan = new Renter(mediator, "小3"); People xiaoWang = new Renter(mediator, "小王"); mediator.registerLandlord(laoWang, Message.builder().msg("我這有2500的房子,市中心").build()); mediator.registerLandlord(laoBai, Message.builder().msg("我這有2000的房子,地鐵旁").build()); mediator.registerLandlord(laoLee, Message.builder().msg("我這有2000的房子,落地陽臺,大空間,採光好,地鐵旁").build()); mediator.registerRenter(xiaoSan); log.info("小3開始找房子"); xiaoSan.sendMessage(Message.builder().msg("想找個月租2000塊的房子,靠近地鐵").build()); log.info("沒過多久---------老白升級了房屋資訊"); laoBai.sendMessage(Message.builder().msg("我這有2000的房子,地鐵旁,我又加了空調和熱水器").build()); mediator.registerRenter(xiaoWang); log.info("小王開始找房子"); xiaoWang.sendMessage(Message.builder().msg("想找個月租2500塊的房子,靠近地鐵").build()); log.info("沒過多久---------老李也升級了房屋資訊"); laoBai.sendMessage(Message.builder().msg("我這有2000的房子,落地陽臺,大空間,採光好,地鐵旁,我也加了空調和熱水器").build()); } } 複製程式碼
最終出效果的如下

現在我來分析下里面各個角色的作用:
首先先分析兩個抽象類。抽象同事類,含有名稱和中介者的引用,有2個方法從中介拿資訊和發信息給中介。抽象中介者,其中含有房東的map資訊,key為房東資料,value為房東的房屋資訊,用來房東註冊和房東房屋資訊變更;租戶的列表資訊,供租戶註冊,同時還有個協調方法,用於協調房東和租戶。
具體抽象類(房地產中介),實現了抽象中介者的協調方法,當租戶傳送訊息時,將租戶的租房條件資訊傳送給所有房東們同時該租戶收到中介那裡所有房東的房屋資訊;當房東傳送訊息時,將房東的房屋資訊傳送給所有租戶們同時變更中介裡的改房東房屋資訊。
具體同事實現類(房東和租戶),實現了抽象同事類的讀取訊息方法和傳送訊息方法(該房屋就是依靠中介者的協調方法來實現)。
JDK中的應用
通過使用一箇中間物件來進行訊息分發以及減少類之間的直接依賴。
java.util.Timer java.util.concurrent.Executor#execute() java.util.concurrent.ExecutorService#submit() java.lang.reflect.Method#invoke()
總結
優點
使用中介者模式可以把對個同事物件之間的互動封裝到中介者物件裡面,從而使得同事物件之間鬆散耦合。 中介者模式可以將原先多對多的同事物件關係變成中介者物件一對多同事物件的關係,這樣會讓物件之間的關係更容易理解和實現。 同事物件之間的互動都被封裝到中介者物件裡面集中管理,集中了控制互動。當交互發生改變時,著重修改的是中介者物件。當需要擴充套件中介者物件時,其他同事物件不需要做修改。