關於 Mediator 本篇將討論以下幾個問題
1. 關於 Mediator
2. UML
3. 將 UML 轉為程式碼
4. 情境
測試環境:
OS:Windows 10
IDE:Visual Studio 2019
1. 關於 Mediator
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
by Gang of Four
- 定義一個一組物件間互動邏輯的封裝(Mediator)
- 透過防止物件之間直接互相引用來減低耦合,並且可以獨立修改其互動邏輯
Mediator(中介者)屬於行為型(Behavioral Patterns),當遇到物件間相互存在複雜引用時,可藉由 Mediator 來將物件間互動邏輯抽離,減低物件之間耦合,之後若需要修改互動邏輯時則不只需要修改 Mediator 而不需要動到物件本身。
優點:
- 符合 單一職責原則(Single Responsibility Principle)
- 符合 開閉原則(Open Closed Principle)
- 快速解除物件間耦合
缺點:
- 過度使用可能會造成 Mediator 演變成 God Class
2. UML
Class 間關聯:
- Colleague 關聯 Mediator
- ConcreteMediator 繼承 Mediator
- ConcreteColleague 繼承 Colleague
- ConcreteMediator 關聯 ConcreteColleague
Class:
- Mediator:中介者的抽象方法或介面
- ConcreteMediator:中介者實作
- Colleague:包含 Mediator 的抽象方法或介面
- ConcreteColleague:Colleague 實作,可經由中介者與其他 ConcreteColleague 互動
3. 將 UML 轉為程式碼
中介者的介面
/// <summary>
/// 中介者的介面
/// </summary>
public interface IMediator
{
void Send(string message, IColleague colleague);
}
中介者實作
/// <summary>
/// 中介者實作
/// </summary>
public class ConcreteMediator : IMediator
{
public IColleague Colleague1 { get; set; }
public IColleague Colleague2 { get; set; }
public void Send(string message, IColleague colleague)
{
if (colleague == Colleague1)
{
Colleague2.Notify(message);
}
else
{
Colleague1.Notify(message);
}
}
}
包含 Mediator 的介面
/// <summary>
/// 包含 Mediator 的介面
/// </summary>
public interface IColleague
{
void Send(string message);
void Notify(string message);
}
Colleague 實作,可經由中介者與其他 ConcreteColleague 互動
/// <summary>
/// Colleague 實作,可經由中介者與其他 ConcreteColleague 互動
/// </summary>
public class ConcreteColleague1 : IColleague
{
private IMediator _mediator { get; }
public ConcreteColleague1(IMediator mediator)
{
_mediator = mediator;
}
public void Send(string message)
{
_mediator.Send(message, this);
}
public void Notify(string message)
{
Console.WriteLine($"Colleague1 gets message: {message}");
}
}
/// <summary>
/// Colleague 實作,可經由中介者與其他 ConcreteColleague 互動
/// </summary>
public class ConcreteColleague2 : IColleague
{
private IMediator _mediator { get; }
public ConcreteColleague2(IMediator mediator)
{
_mediator = mediator;
}
public void Send(string message)
{
_mediator.Send(message, this);
}
public void Notify(string message)
{
Console.WriteLine($"Colleague2 gets message: {message}");
}
}
- 建立
mediator
- 將
mediator
傳入colleague1
&colleague2
- 再將
colleague1
&colleague2
指定給mediator
colleague1
&colleague2
經由mediator
互動
static void Main(string[] args)
{
#region Default
Default.ConcreteMediator mediator = new Default.ConcreteMediator();
Default.ConcreteColleague1 colleague1 = new Default.ConcreteColleague1(mediator);
Default.ConcreteColleague2 colleague2 = new Default.ConcreteColleague2(mediator);
mediator.Colleague1 = colleague1;
mediator.Colleague2 = colleague2;
colleague1.Send("How are you?");
colleague2.Send("Fine, thanks.");
Console.ReadLine();
#endregion
}
執行結果
Colleague2 gets message: How are you?
Colleague1 gets message: Fine, thanks.
4. 情境
我們接到了一個門市取得其他分店庫存的需求
- 不同店之間要能夠取得對方庫存資訊以互相支援
- 各分店販售商品不完全相同,故撈取資料參數不同
中介者的介面
/// <summary>
/// 中介者的介面
/// </summary>
public interface IMediator
{
void GetOtherStoreInStore(IStore store);
}
中介者實作
/// <summary>
/// 中介者實作
/// </summary>
public class Mediator : IMediator
{
public IStore StoreDaan { get; set; }
public IStore StoreXinyi { get; set; }
public void GetOtherStoreInStore(IStore store)
{
if (store == StoreDaan)
{
StoreXinyi.GetInStore();
}
else
{
StoreDaan.GetInStore();
}
}
}
包含 Mediator 的門市介面
/// <summary>
/// 包含 Mediator 的門市介面
/// </summary>
public interface IStore
{
void GetInStore();
}
門市間可透過 Mediator 取得其他分店庫存
/// <summary>
/// 大安店實作,透過 Mediator 取得信義店庫存
/// </summary>
public class StoreDaan : IStore
{
private IMediator _mediator { get; }
public StoreDaan(IMediator mediator)
{
_mediator = mediator;
}
public void GetOtherStoreInStore()
{
_mediator.GetOtherStoreInStore(this);
}
public void GetInStore()
{
Console.WriteLine($"大安店 目前庫存 咖啡 100 杯,蛋糕 5 片");
}
}
/// <summary>
/// 信義店實作,透過 Mediator 取得大安店庫存
/// </summary>
public class StoreXinyi : IStore
{
private IMediator _mediator { get; }
public StoreXinyi(IMediator mediator)
{
_mediator = mediator;
}
public void GetOtherStoreInStore()
{
_mediator.GetOtherStoreInStore(this);
}
public void GetInStore()
{
Console.WriteLine($"信義店 目前庫存 咖啡 10 杯,蛋糕 120 片");
}
}
- 建立
mediator
- 將
mediator
傳入storeDaan
&storeXinyi
- 再將
storeDaan
&storeXinyi
指定給mediator
- 大安店經由
mediator
取得信義店庫存
static void Main(string[] args)
{
Situation.Mediator mediator = new Situation.Mediator();
Situation.StoreDaan storeDaan = new Situation.StoreDaan(mediator);
Situation.StoreXinyi storeXinyi = new Situation.StoreXinyi(mediator);
mediator.StoreDaan = storeDaan;
mediator.StoreXinyi = storeXinyi;
storeDaan.GetInStore();
storeDaan.GetOtherStoreInStore();
Console.ReadLine();
}
執行結果
大安店 目前庫存 咖啡 100 杯,蛋糕 5 片
信義店 目前庫存 咖啡 10 杯,蛋糕 120 片
完整程式碼
GitHub:Behavioral_05_Mediator