前言
這篇文章主要介紹Mediator Pattern的定義以及簡單實作
介紹使用Mediator Pattern的好處, 並提供範例
在軟體架構中Mediator Patternc和Repository Pattern都是常用的pattern
通常.NET專案中會結合MediatR套件使用
IG貼文:
Mediator Pattern Post
GitHub連結:
Sample Code
定義一個 Mediator 物件用來封裝一組物件的互動方式。
Mediator 藉由避免物件間相互直接的引用,從而降低它們之間的耦合程度,並且可以讓我們獨立地改變這些物件間的互動方式。
下面這兩張圖片可以簡單體現出Mediator Pattern在做的事
沒有使用中介者, 物件彼此之間直接調用
使用中介者, 物件只依賴mediator來與其他物件溝通
可以發現使用中介者模式之後, 物件都只依賴中介者來傳遞訊息, 而不是直接調用彼此, 以此達到解耦。
在現實生活中, 也有類似的例子, 例如開發團隊, 客服團隊, 產銷團隊, 設計團隊, 若彼此之間沒有一個統一的溝通,
那麼各個團隊耦合度很高, 開發跟設計要協調介面, 又要和產銷和客服討論如何贏得如何符合市場, 這樣一來分工太複雜。
所以需要一個產品經理來當中介者, 協助溝通各個團隊。
優缺點
- 優點
- 降低物件之間的耦合性,讓物件容易重複使用。
- 物件之間一對多的關聯性變成一對一,提高系統靈活性,也讓整體容易維護及擴充。
- 缺點 (Trade-off)
- 同事類別過多時,中介者責任很大,會使系統提升一定程度的複雜性。
UML與成員
成員 |
定義 |
Mdiator |
抽象中介者, 定義註冊進入mediator以及轉發的方法 |
ConcreteMediator |
具體中介者, 定義一個集合來管理同事, 所以聚合Colleague |
Colleague |
抽象同事, 可以保存中介者, 調用內部方法, 所以聚合Mediator |
ConcreteColleague |
具體同事, 當要跟其他物件溝通時, 利用內部的中介者進行轉發 |
實作
專案結構
抽象Mediator
Mediator(抽象)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| using System; using MediatorPattern.colleagues;
namespace MediatorPattern.mediator { public enum teamType { ENGINEERING, DESIGN, SERVICE, MARKETING }
public abstract class Mediator { public abstract void Register(teamType type, Colleague colleague); public abstract void Relay(teamType type, string msg); } }
|
PackageManager(具體Mediator)
PackageManager(具體Mediator)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| using System; using MediatorPattern.colleagues;
namespace MediatorPattern.mediator { public class ProductManager : Mediator { private Dictionary<teamType, Colleague> colleagues = new Dictionary<teamType, Colleague>();
public override void Register(teamType type, Colleague colleague) { colleague.setMediator(this); this.colleagues.Add(type, colleague); }
public override void Relay(teamType type, string msg) { Colleague toColleague = this.colleagues[type]; toColleague.receive(msg); } } }
|
抽象Colleague
Colleague(抽象)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| using System; using MediatorPattern.mediator;
namespace MediatorPattern.colleagues { public abstract class Colleague { protected Mediator? Mediator { get; private set; }
public void setMediator(Mediator mediator) { this.Mediator = mediator; }
public abstract void receive(string msg);
public abstract void send(teamType type, string msg); } }
|
具體Colleague
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| public class DesignTeam : Colleague { public override void receive(string msg) { Console.WriteLine("設計團隊收到訊息: " + msg); }
public override void send(teamType type, string msg) { Console.WriteLine("設計團隊發送訊息: "+msg); if (this.Mediator != null) { this.Mediator.Relay(type, msg); } } }
public class EngineeringTeam : Colleague { public override void receive(string msg) { Console.WriteLine("工程師團隊收到訊息: "+msg); }
public override void send(teamType type, string msg) { Console.WriteLine("工程師團隊發送訊息: "+msg); if (this.Mediator != null) { this.Mediator.Relay(type, msg); } } }
public class MarketingTeam : Colleague { public override void receive(string msg) { Console.WriteLine("產銷團隊收到訊息: " + msg); }
public override void send(teamType type, string msg) { Console.WriteLine("產銷團隊發送訊息: "+msg); if (this.Mediator != null) { this.Mediator.Relay(type, msg); } } }
public class ServiceTeam : Colleague { public override void receive(string msg) { Console.WriteLine("客服團隊收到訊息: " + msg); }
public override void send(teamType type, string msg) { Console.WriteLine("客服團隊發送訊息: "+msg); if (this.Mediator != null) { this.Mediator.Relay(type, msg); } } }
|
Client端使用
Program.cs1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| using MediatorPattern.colleagues; using MediatorPattern.mediator;
ProductManager pm = new ProductManager();
Colleague ds = new DesignTeam(); Colleague eg = new EngineeringTeam(); Colleague mk = new MarketingTeam(); Colleague sv = new ServiceTeam();
pm.Register(teamType.DESIGN, ds); pm.Register(teamType.ENGINEERING, eg); pm.Register(teamType.MARKETING, mk); pm.Register(teamType.SERVICE, sv);
ds.send(teamType.ENGINEERING, "UI設計稿完成"); Console.WriteLine(String.Concat(Enumerable.Repeat("-", 10)));
eg.send(teamType.MARKETING, "軟體開發完成"); Console.WriteLine(String.Concat(Enumerable.Repeat("-", 10)));
Console.ReadKey();
|
結果
疑問
- DI不也是讓物件間解耦嗎?他們有什麼不同?
- 應用場景不同:Mediator模式主要用於解耦合多個相互協作的物件,特別是在複雜的互動場景中。DI則主要用於管理和注入依賴關係,以實現鬆耦合和可測試的程式碼。
- 解決不同問題:Mediator解決的是物件之間的協作和通信問題,而DI解決的是依賴關係管理的問題。
- 實現方式不同:Mediator需要一個中介者來協調物件之間的互動,通常由一個專門的Mediator類別來實現。DI則是一種設計模式,它可以與不同語言和框架一起使用,並不需要特定的中介者類別。
結語
- 定義:
定義一個 Mediator 物件用來封裝一組物件的互動方式。Mediator 藉由避免物件間相互直接的引用,從而降低它們之間的耦合程度,並且可以讓我們獨立地改變這些物件間的互動方式。
- 成員
- 抽象Mediator: 定義方法, 轉接訊息
- 具體Mediator: 實作抽象Mediator, Colleague (擁有0~多個Colleague)
- 抽象Colleague: 定義方法, 聚合抽象Mediator (Colleague擁有Mediator)
- 具體Colleague: 實作抽象Mediator
- 優點
- 降低物件之間的耦合性,讓物件容易重複使用。
- 物件之間一對多的關聯性變成一對一,提高系統靈活性,也讓整體容易維護及擴充。
- 缺點 (Trade-off)
- 同事類別過多時,中介者責任很大,會使系統提升一定程度的複雜性。