C#和Unity中的中介者模式使用方式
C#中的中介者模式詳解
中介者模式(Mediator Pattern)是一種行為設(shè)計(jì)模式,它能減少對(duì)象之間混亂無(wú)序的依賴關(guān)系,通過(guò)引入一個(gè)中介者對(duì)象來(lái)封裝一系列對(duì)象之間的交互。
一、中介者模式的基本概念
1. 定義
中介者模式定義了一個(gè)對(duì)象來(lái)封裝一組對(duì)象之間的交互方式,使各對(duì)象不需要顯式地相互引用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互。
2. 組成要素
- Mediator(中介者接口) :定義各個(gè)同事對(duì)象通信的接口
- ConcreteMediator(具體中介者) :實(shí)現(xiàn)中介者接口,協(xié)調(diào)各同事對(duì)象的交互
- Colleague(同事類) :每個(gè)同事對(duì)象都知道它的中介者對(duì)象,與其他同事通信時(shí)都通過(guò)中介者
3. 模式結(jié)構(gòu)
[同事A] ────> [中介者] <─── [同事B]
↑____________|____________↑
二、中介者模式的特點(diǎn)
1. 優(yōu)點(diǎn)
- 降低耦合度:將對(duì)象之間的網(wǎng)狀結(jié)構(gòu)變?yōu)樾切徒Y(jié)構(gòu)
- 集中控制:將交互復(fù)雜性集中到中介者中
- 簡(jiǎn)化對(duì)象協(xié)議:用一對(duì)多的交互代替多對(duì)多的交互
- 易于擴(kuò)展:新增同事類只需修改中介者或新增具體中介者
2. 缺點(diǎn)
- 中介者可能變得復(fù)雜:如果同事類過(guò)多,中介者會(huì)變得龐大復(fù)雜
- 過(guò)度集中化:中介者集中了太多控制邏輯,可能成為"上帝對(duì)象"
三、中介者模式的實(shí)現(xiàn)方式
1. 基本實(shí)現(xiàn)
// 中介者接口
public interface IMediator
{
void Notify(object sender, string ev);
}
// 基礎(chǔ)同事類
public abstract class Colleague
{
protected IMediator _mediator;
public Colleague(IMediator mediator)
{
_mediator = mediator;
}
}
// 具體同事A
public class ConcreteColleagueA : Colleague
{
public ConcreteColleagueA(IMediator mediator) : base(mediator) { }
public void DoA()
{
Console.WriteLine("ColleagueA does A.");
_mediator.Notify(this, "A");
}
public void DoB()
{
Console.WriteLine("ColleagueA does B.");
}
}
// 具體同事B
public class ConcreteColleagueB : Colleague
{
public ConcreteColleagueB(IMediator mediator) : base(mediator) { }
public void DoC()
{
Console.WriteLine("ColleagueB does C.");
_mediator.Notify(this, "C");
}
public void DoD()
{
Console.WriteLine("ColleagueB does D.");
}
}
// 具體中介者
public class ConcreteMediator : IMediator
{
private ConcreteColleagueA _colleagueA;
private ConcreteColleagueB _colleagueB;
public ConcreteColleagueA ColleagueA
{
set { _colleagueA = value; }
}
public ConcreteColleagueB ColleagueB
{
set { _colleagueB = value; }
}
public void Notify(object sender, string ev)
{
if (ev == "A")
{
Console.WriteLine("Mediator reacts on A and triggers:");
_colleagueB.DoC();
}
if (ev == "C")
{
Console.WriteLine("Mediator reacts on C and triggers:");
_colleagueA.DoB();
_colleagueB.DoD();
}
}
}
2. 使用示例
// 客戶端代碼
var mediator = new ConcreteMediator();
var colleagueA = new ConcreteColleagueA(mediator);
var colleagueB = new ConcreteColleagueB(mediator);
mediator.ColleagueA = colleagueA;
mediator.ColleagueB = colleagueB;
Console.WriteLine("Client triggers operation A.");
colleagueA.DoA();
Console.WriteLine();
Console.WriteLine("Client triggers operation C.");
colleagueB.DoC();
3. 更復(fù)雜的實(shí)現(xiàn)(聊天室示例)
// 中介者接口
public interface IChatRoom
{
void Register(Participant participant);
void Send(string from, string to, string message);
}
// 具體中介者 - 聊天室
public class ChatRoom : IChatRoom
{
private Dictionary<string, Participant> _participants = new Dictionary<string, Participant>();
public void Register(Participant participant)
{
if (!_participants.ContainsKey(participant.Name))
{
_participants.Add(participant.Name, participant);
}
participant.ChatRoom = this;
}
public void Send(string from, string to, string message)
{
if (_participants.TryGetValue(to, out var participant))
{
participant.Receive(from, message);
}
}
}
// 同事基類
public abstract class Participant
{
public string Name { get; }
public IChatRoom ChatRoom { get; set; }
protected Participant(string name)
{
Name = name;
}
public void Send(string to, string message)
{
ChatRoom.Send(Name, to, message);
}
public abstract void Receive(string from, string message);
}
// 具體同事類
public class User : Participant
{
public User(string name) : base(name) { }
public override void Receive(string from, string message)
{
Console.WriteLine($"{from} to {Name}: '{message}'");
}
}
// 使用
var chatRoom = new ChatRoom();
var john = new User("John");
var jane = new User("Jane");
chatRoom.Register(john);
chatRoom.Register(jane);
john.Send("Jane", "Hi Jane!");
jane.Send("John", "Hello John!");
四、中介者模式的使用場(chǎng)景
1. 典型使用場(chǎng)景
- 對(duì)象間存在復(fù)雜的引用關(guān)系:當(dāng)系統(tǒng)中對(duì)象之間存在復(fù)雜的網(wǎng)狀引用關(guān)系,導(dǎo)致系統(tǒng)結(jié)構(gòu)混亂且難以理解時(shí)。
- 需要集中控制對(duì)象間的交互:當(dāng)多個(gè)類之間有復(fù)雜的交互邏輯,且這些邏輯需要集中管理時(shí)。
- 想定制分布在多個(gè)類中的行為:當(dāng)行為分布在多個(gè)類中,但又需要根據(jù)需求改變這些行為時(shí)。
- GUI組件交互:圖形用戶界面中,各種控件(按鈕、文本框等)之間的交互。
- 消息傳遞系統(tǒng):如聊天應(yīng)用、通知系統(tǒng)等需要多方通信的場(chǎng)景。
2. 實(shí)際應(yīng)用示例
示例1:航空管制系統(tǒng)
// 航空交通管制中介者接口
public interface IAirTrafficControl
{
// 注冊(cè)飛機(jī)到管制系統(tǒng)
void RegisterAircraft(Aircraft aircraft);
// 發(fā)送警告消息(發(fā)送者飛機(jī) + 消息內(nèi)容)
void SendWarningMessage(Aircraft sender, string message);
}
// 飛機(jī)類(同事類)
public class Aircraft
{
// 飛機(jī)呼號(hào)(唯一標(biāo)識(shí))
public string CallSign { get; }
// 持有對(duì)航空管制中心(中介者)的引用
private IAirTrafficControl _atc;
// 構(gòu)造函數(shù):初始化飛機(jī)并注冊(cè)到管制系統(tǒng)
public Aircraft(string callSign, IAirTrafficControl atc)
{
CallSign = callSign;
_atc = atc;
_atc.RegisterAircraft(this); // 自動(dòng)注冊(cè)到管制系統(tǒng)
}
// 發(fā)送警告消息(通過(guò)管制中心轉(zhuǎn)發(fā))
public void SendWarning(string message)
{
// 不直接聯(lián)系其他飛機(jī),而是通過(guò)管制中心發(fā)送
_atc.SendWarningMessage(this, message);
}
// 接收來(lái)自其他飛機(jī)的警告
public void ReceiveWarning(string from, string message)
{
// 打印接收到的警告信息
Console.WriteLine($"{CallSign} received from {from}: {message}");
}
}
// 塔臺(tái)管制中心(具體中介者實(shí)現(xiàn))
public class Tower : IAirTrafficControl
{
// 保存所有注冊(cè)的飛機(jī)列表
private List<Aircraft> _aircrafts = new List<Aircraft>();
// 注冊(cè)飛機(jī)到管制系統(tǒng)
public void RegisterAircraft(Aircraft aircraft)
{
// 防止重復(fù)注冊(cè)
if (!_aircrafts.Contains(aircraft))
{
_aircrafts.Add(aircraft);
}
}
// 處理警告消息轉(zhuǎn)發(fā)
public void SendWarningMessage(Aircraft sender, string message)
{
// 遍歷所有已注冊(cè)的飛機(jī)(排除發(fā)送者自己)
foreach (var aircraft in _aircrafts.Where(a => a != sender))
{
// 將消息轉(zhuǎn)發(fā)給其他飛機(jī)
aircraft.ReceiveWarning(sender.CallSign, message);
}
}
}
示例2:訂單處理系統(tǒng)
// 訂單中介者接口
public interface IOrderMediator
{
// 通知方法:組件通過(guò)此方法與中介者通信
// sender - 觸發(fā)事件的組件
// eventType - 事件類型標(biāo)識(shí)
void Notify(OrderComponent sender, string eventType);
}
// 訂單組件基類(抽象同事類)
public abstract class OrderComponent
{
// 持有對(duì)中介者的引用
protected IOrderMediator _mediator;
// 構(gòu)造函數(shù):注入中介者實(shí)例
public OrderComponent(IOrderMediator mediator)
{
_mediator = mediator;
}
}
// 庫(kù)存系統(tǒng)(具體同事類)
public class InventorySystem : OrderComponent
{
// 構(gòu)造函數(shù):調(diào)用基類構(gòu)造函數(shù)
public InventorySystem(IOrderMediator mediator) : base(mediator) { }
// 檢查庫(kù)存方法
public void CheckStock()
{
Console.WriteLine("Checking stock...");
// 通知中介者庫(kù)存已檢查
_mediator.Notify(this, "StockChecked");
}
// 更新庫(kù)存方法
public void UpdateStock()
{
Console.WriteLine("Updating stock...");
}
}
// 支付系統(tǒng)(具體同事類)
public class PaymentSystem : OrderComponent
{
// 構(gòu)造函數(shù):調(diào)用基類構(gòu)造函數(shù)
public PaymentSystem(IOrderMediator mediator) : base(mediator) { }
// 處理支付方法
public void ProcessPayment()
{
Console.WriteLine("Processing payment...");
// 通知中介者支付已處理
_mediator.Notify(this, "PaymentProcessed");
}
}
// 訂單中介者實(shí)現(xiàn)(具體中介者)
public class OrderMediator : IOrderMediator
{
// 持有庫(kù)存系統(tǒng)引用
private InventorySystem _inventory;
// 持有支付系統(tǒng)引用
private PaymentSystem _payment;
// 構(gòu)造函數(shù):注入需要的組件
public OrderMediator(InventorySystem inventory, PaymentSystem payment)
{
_inventory = inventory;
_payment = payment;
}
// 實(shí)現(xiàn)通知處理方法
public void Notify(OrderComponent sender, string eventType)
{
// 如果是庫(kù)存系統(tǒng)且事件類型為"StockChecked"
if (sender is InventorySystem && eventType == "StockChecked")
{
// 觸發(fā)支付系統(tǒng)處理支付
_payment.ProcessPayment();
}
// 如果是支付系統(tǒng)且事件類型為"PaymentProcessed"
else if (sender is PaymentSystem && eventType == "PaymentProcessed")
{
// 更新庫(kù)存
_inventory.UpdateStock();
Console.WriteLine("Order completed!");
}
}
}
五、中介者模式與其他模式的關(guān)系
與外觀模式的區(qū)別:
- 外觀模式為子系統(tǒng)提供簡(jiǎn)化接口,但不添加新功能
- 中介者模式集中同事對(duì)象間的通信,可以添加協(xié)調(diào)邏輯
與觀察者模式的區(qū)別:
- 觀察者模式通過(guò)訂閱/發(fā)布機(jī)制實(shí)現(xiàn)單向通信
- 中介者模式對(duì)象間通過(guò)中介者進(jìn)行雙向通信
與命令模式結(jié)合:
- 可以使用命令模式將請(qǐng)求封裝為對(duì)象,由中介者管理這些命令
六、最佳實(shí)踐
合理劃分責(zé)任:
- 中介者應(yīng)只負(fù)責(zé)協(xié)調(diào),不承擔(dān)業(yè)務(wù)邏輯
- 避免創(chuàng)建"上帝對(duì)象"
考慮使用事件:
- 在C#中可以使用事件機(jī)制實(shí)現(xiàn)輕量級(jí)中介者
適度使用:
- 只在對(duì)象間交互確實(shí)復(fù)雜時(shí)使用
- 簡(jiǎn)單交互直接引用可能更合適
可測(cè)試性設(shè)計(jì):
- 使中介者易于替換,方便單元測(cè)試
性能考慮:
- 高頻交互場(chǎng)景需評(píng)估中介者帶來(lái)的性能影響
七、總結(jié)
中介者模式是管理復(fù)雜對(duì)象交互的強(qiáng)大工具,特別適用于以下場(chǎng)景:
- 對(duì)象間存在大量直接連接
- 系統(tǒng)組件難以復(fù)用
- 交互邏輯分散難以理解
- 需要集中控制對(duì)象間通信
在C#中實(shí)現(xiàn)中介者模式時(shí),可以:
- 定義清晰的中介者接口
- 使同事類只依賴于中介者
- 將復(fù)雜的交互邏輯封裝在中介者中
- 考慮使用事件或委托簡(jiǎn)化實(shí)現(xiàn)
正確使用中介者模式可以顯著降低系統(tǒng)復(fù)雜度,提高代碼的可維護(hù)性和靈活性。
八、使用事件或委托簡(jiǎn)化實(shí)現(xiàn)中介者模式
中介者模式可以通過(guò)C#的事件和委托機(jī)制來(lái)簡(jiǎn)化實(shí)現(xiàn),這種方式可以減少中介者類的復(fù)雜性,同時(shí)保持對(duì)象間的解耦。下面我將展示如何使用事件來(lái)重構(gòu)中介者模式。
1. 基于事件的簡(jiǎn)化實(shí)現(xiàn)
基本架構(gòu)
// 定義事件參數(shù)基類
public abstract class OrderEventArgs : EventArgs
{
public string EventType { get; set; }
}
// 庫(kù)存系統(tǒng)事件參數(shù)
public class InventoryEventArgs : OrderEventArgs
{
public int ProductId { get; set; }
public int Quantity { get; set; }
}
// 支付系統(tǒng)事件參數(shù)
public class PaymentEventArgs : OrderEventArgs
{
public decimal Amount { get; set; }
public string PaymentMethod { get; set; }
}
// 訂單組件基類(使用事件)
public abstract class OrderComponent
{
// 定義事件處理器委托
public delegate void OrderEventHandler(object sender, OrderEventArgs e);
// 組件事件
public event OrderEventHandler OnOrderEvent;
// 觸發(fā)事件的方法
protected void RaiseEvent(OrderEventArgs e)
{
OnOrderEvent?.Invoke(this, e);
}
}
// 庫(kù)存系統(tǒng)實(shí)現(xiàn)
public class InventorySystem : OrderComponent
{
public void CheckStock(int productId)
{
Console.WriteLine($"Checking stock for product {productId}...");
RaiseEvent(new InventoryEventArgs {
EventType = "StockChecked",
ProductId = productId,
Quantity = 100 // 假設(shè)檢查到有100個(gè)庫(kù)存
});
}
public void UpdateStock(int productId, int quantity)
{
Console.WriteLine($"Updating stock for product {productId}, quantity: {quantity}");
}
}
// 支付系統(tǒng)實(shí)現(xiàn)
public class PaymentSystem : OrderComponent
{
public void ProcessPayment(decimal amount, string method)
{
Console.WriteLine($"Processing payment of {amount} via {method}");
RaiseEvent(new PaymentEventArgs {
EventType = "PaymentProcessed",
Amount = amount,
PaymentMethod = method
});
}
}
事件協(xié)調(diào)器(輕量級(jí)中介者)
public class OrderEventCoordinator
{
private readonly InventorySystem _inventory;
private readonly PaymentSystem _payment;
public OrderEventCoordinator(InventorySystem inventory, PaymentSystem payment)
{
_inventory = inventory;
_payment = payment;
// 訂閱庫(kù)存系統(tǒng)事件
_inventory.OnOrderEvent += HandleInventoryEvent;
// 訂閱支付系統(tǒng)事件
_payment.OnOrderEvent += HandlePaymentEvent;
}
private void HandleInventoryEvent(object sender, OrderEventArgs e)
{
if (e is InventoryEventArgs args && args.EventType == "StockChecked")
{
// 庫(kù)存檢查完成后處理支付
_payment.ProcessPayment(99.99m, "CreditCard");
}
}
private void HandlePaymentEvent(object sender, OrderEventArgs e)
{
if (e is PaymentEventArgs args && args.EventType == "PaymentProcessed")
{
// 支付完成后更新庫(kù)存
_inventory.UpdateStock(1, -1); // 假設(shè)產(chǎn)品ID為1,減少1個(gè)庫(kù)存
Console.WriteLine("Order completed!");
}
}
}
2. 使用Action委托的簡(jiǎn)化實(shí)現(xiàn)
更輕量的實(shí)現(xiàn)方式
// 組件基類(使用Action委托)
public abstract class OrderComponent
{
protected Action<string, object> MediatorCallback { get; }
public OrderComponent(Action<string, object> mediatorCallback)
{
MediatorCallback = mediatorCallback;
}
}
// 庫(kù)存系統(tǒng)
public class InventorySystem : OrderComponent
{
public InventorySystem(Action<string, object> callback) : base(callback) {}
public void CheckStock(int productId)
{
Console.WriteLine($"Checking stock for product {productId}...");
MediatorCallback?.Invoke("StockChecked", new { ProductId = productId });
}
public void UpdateStock(int productId, int quantity)
{
Console.WriteLine($"Updating stock for product {productId}, quantity: {quantity}");
}
}
// 支付系統(tǒng)
public class PaymentSystem : OrderComponent
{
public PaymentSystem(Action<string, object> callback) : base(callback) {}
public void ProcessPayment(decimal amount, string method)
{
Console.WriteLine($"Processing payment of {amount} via {method}");
MediatorCallback?.Invoke("PaymentProcessed", new { Amount = amount, Method = method });
}
}
// 使用Lambda表達(dá)式作為中介者
public class Program
{
public static void Main()
{
// 創(chuàng)建支付系統(tǒng)并定義其回調(diào)
var payment = new PaymentSystem((eventType, data) =>
{
if (eventType == "PaymentProcessed")
{
Console.WriteLine("Payment processed callback");
}
});
// 創(chuàng)建庫(kù)存系統(tǒng)并定義完整流程
var inventory = new InventorySystem((eventType, data) =>
{
dynamic eventData = data;
if (eventType == "StockChecked")
{
Console.WriteLine($"Stock checked for product {eventData.ProductId}");
payment.ProcessPayment(99.99m, "CreditCard");
}
else if (eventType == "PaymentProcessed")
{
inventory.UpdateStock(1, -1);
Console.WriteLine("Order completed!");
}
});
// 啟動(dòng)流程
inventory.CheckStock(1);
}
}
3. 使用.NET內(nèi)置EventBus的簡(jiǎn)化實(shí)現(xiàn)
基于MediatR庫(kù)的實(shí)現(xiàn)
// 安裝MediatR NuGet包
// Install-Package MediatR
// 定義事件/通知
public class StockCheckedEvent : INotification
{
public int ProductId { get; set; }
}
public class PaymentProcessedEvent : INotification
{
public decimal Amount { get; set; }
}
// 定義處理器
public class StockCheckedHandler : INotificationHandler<StockCheckedEvent>
{
private readonly IMediator _mediator;
public StockCheckedHandler(IMediator mediator)
{
_mediator = mediator;
}
public async Task Handle(StockCheckedEvent notification, CancellationToken ct)
{
Console.WriteLine($"Stock checked for product {notification.ProductId}");
await _mediator.Publish(new PaymentProcessedEvent { Amount = 99.99m }, ct);
}
}
public class PaymentProcessedHandler : INotificationHandler<PaymentProcessedEvent>
{
public Task Handle(PaymentProcessedEvent notification, CancellationToken ct)
{
Console.WriteLine($"Payment processed: {notification.Amount}");
Console.WriteLine("Order completed!");
return Task.CompletedTask;
}
}
// 使用示例
var services = new ServiceCollection();
services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
var provider = services.BuildServiceProvider();
var mediator = provider.GetRequiredService<IMediator>();
await mediator.Publish(new StockCheckedEvent { ProductId = 1 });
4. 比較與選擇
| 實(shí)現(xiàn)方式 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場(chǎng)景 |
|---|---|---|---|
| 經(jīng)典中介者模式 | 結(jié)構(gòu)清晰,職責(zé)明確 | 中介者類可能變得龐大 | 復(fù)雜交互,需要集中控制 |
| 基于事件實(shí)現(xiàn) | 松耦合,易于擴(kuò)展 | 事件處理邏輯分散 | 組件間交互簡(jiǎn)單,需要靈活擴(kuò)展 |
| Action委托回調(diào) | 實(shí)現(xiàn)簡(jiǎn)單,輕量級(jí) | 不適合復(fù)雜交互 | 簡(jiǎn)單流程,快速實(shí)現(xiàn) |
| MediatR事件總線 | 專業(yè)解耦,支持異步 | 需要引入第三方庫(kù) | 企業(yè)級(jí)應(yīng)用,需要強(qiáng)大事件處理 |
5. 最佳實(shí)踐建議
- 簡(jiǎn)單場(chǎng)景:使用Action委托或簡(jiǎn)單事件實(shí)現(xiàn)
- 中等復(fù)雜度:使用基于事件的協(xié)調(diào)器模式
- 企業(yè)級(jí)應(yīng)用:考慮使用MediatR等事件總線庫(kù)
- 保持一致性:項(xiàng)目中統(tǒng)一使用一種實(shí)現(xiàn)方式
- 適度抽象:不要過(guò)度設(shè)計(jì),根據(jù)實(shí)際需求選擇
八、在Unity中的應(yīng)用
示例1:UI系統(tǒng)管理
using UnityEngine;
using UnityEngine.UI;
// 中介者接口
public interface IUIMediator
{
void Notify(UIComponent sender, string eventName);
}
// 具體中介者 - UI管理器
public class UIManager : MonoBehaviour, IUIMediator
{
public Button startButton;
public Button optionsButton;
public Button quitButton;
public GameObject mainMenuPanel;
public GameObject optionsPanel;
private void Start()
{
// 為每個(gè)UI組件設(shè)置中介者引用
startButton.GetComponent<UIComponent>().SetMediator(this);
optionsButton.GetComponent<UIComponent>().SetMediator(this);
quitButton.GetComponent<UIComponent>().SetMediator(this);
// 初始化UI狀態(tài)
mainMenuPanel.SetActive(true);
optionsPanel.SetActive(false);
}
// 處理UI組件通知
public void Notify(UIComponent sender, string eventName)
{
switch (eventName)
{
case "StartButtonClicked":
OnStartGame();
break;
case "OptionsButtonClicked":
OnOpenOptions();
break;
case "QuitButtonClicked":
OnQuitGame();
break;
case "BackButtonClicked":
OnBackToMenu();
break;
}
}
private void OnStartGame()
{
Debug.Log("開(kāi)始游戲");
mainMenuPanel.SetActive(false);
// 這里可以添加游戲開(kāi)始的邏輯
}
private void OnOpenOptions()
{
Debug.Log("打開(kāi)選項(xiàng)菜單");
mainMenuPanel.SetActive(false);
optionsPanel.SetActive(true);
}
private void OnQuitGame()
{
Debug.Log("退出游戲");
Application.Quit();
}
private void OnBackToMenu()
{
Debug.Log("返回主菜單");
optionsPanel.SetActive(false);
mainMenuPanel.SetActive(true);
}
}
// 同事類 - UI組件基類
public class UIComponent : MonoBehaviour
{
protected IUIMediator mediator;
// 設(shè)置中介者
public void SetMediator(IUIMediator mediator)
{
this.mediator = mediator;
}
// 通知中介者
protected void NotifyMediator(string eventName)
{
mediator?.Notify(this, eventName);
}
}
// 具體同事類 - 開(kāi)始按鈕
public class StartButton : UIComponent
{
private Button button;
private void Awake()
{
button = GetComponent<Button>();
button.onClick.AddListener(OnClick);
}
private void OnClick()
{
NotifyMediator("StartButtonClicked");
}
}
// 具體同事類 - 選項(xiàng)按鈕
public class OptionsButton : UIComponent
{
private Button button;
private void Awake()
{
button = GetComponent<Button>();
button.onClick.AddListener(OnClick);
}
private void OnClick()
{
NotifyMediator("OptionsButtonClicked");
}
}
// 具體同事類 - 退出按鈕
public class QuitButton : UIComponent
{
private Button button;
private void Awake()
{
button = GetComponent<Button>();
button.onClick.AddListener(OnClick);
}
private void OnClick()
{
NotifyMediator("QuitButtonClicked");
}
}
// 具體同事類 - 返回按鈕
public class BackButton : UIComponent
{
private Button button;
private void Awake()
{
button = GetComponent<Button>();
button.onClick.AddListener(OnClick);
}
private void OnClick()
{
NotifyMediator("BackButtonClicked");
}
}
示例2:游戲事件系統(tǒng)
using UnityEngine;
using System.Collections.Generic;
// 事件類型枚舉
public enum GameEventType
{
PlayerDied,
EnemyKilled,
ItemCollected,
LevelCompleted
}
// 中介者接口
public interface IGameEventMediator
{
void Subscribe(GameEventType eventType, IGameEventSubscriber subscriber);
void Unsubscribe(GameEventType eventType, IGameEventSubscriber subscriber);
void Publish(GameEventType eventType, object sender, object eventData);
}
// 具體中介者 - 游戲事件管理器
public class GameEventManager : MonoBehaviour, IGameEventMediator
{
private Dictionary<GameEventType, List<IGameEventSubscriber>> subscribers =
new Dictionary<GameEventType, List<IGameEventSubscriber>>();
// 訂閱事件
public void Subscribe(GameEventType eventType, IGameEventSubscriber subscriber)
{
if (!subscribers.ContainsKey(eventType))
{
subscribers[eventType] = new List<IGameEventSubscriber>();
}
if (!subscribers[eventType].Contains(subscriber))
{
subscribers[eventType].Add(subscriber);
}
}
// 取消訂閱
public void Unsubscribe(GameEventType eventType, IGameEventSubscriber subscriber)
{
if (subscribers.ContainsKey(eventType))
{
subscribers[eventType].Remove(subscriber);
}
}
// 發(fā)布事件
public void Publish(GameEventType eventType, object sender, object eventData)
{
if (subscribers.ContainsKey(eventType))
{
foreach (var subscriber in subscribers[eventType])
{
subscriber.OnEvent(eventType, sender, eventData);
}
}
}
}
// 同事接口 - 事件訂閱者
public interface IGameEventSubscriber
{
void OnEvent(GameEventType eventType, object sender, object eventData);
}
// 具體同事類 - 玩家控制器
public class PlayerController : MonoBehaviour, IGameEventSubscriber
{
private IGameEventMediator eventMediator;
public int health = 100;
private void Start()
{
eventMediator = FindObjectOfType<GameEventManager>();
eventMediator.Subscribe(GameEventType.PlayerDied, this);
}
private void OnDestroy()
{
eventMediator?.Unsubscribe(GameEventType.PlayerDied, this);
}
public void TakeDamage(int damage)
{
health -= damage;
if (health <= 0)
{
eventMediator.Publish(GameEventType.PlayerDied, this, null);
}
}
public void OnEvent(GameEventType eventType, object sender, object eventData)
{
if (eventType == GameEventType.PlayerDied && sender == this)
{
Debug.Log("玩家死亡事件處理");
// 處理玩家死亡邏輯
}
}
}
// 具體同事類 - 成就系統(tǒng)
public class AchievementSystem : MonoBehaviour, IGameEventSubscriber
{
private IGameEventMediator eventMediator;
private void Start()
{
eventMediator = FindObjectOfType<GameEventManager>();
eventMediator.Subscribe(GameEventType.EnemyKilled, this);
eventMediator.Subscribe(GameEventType.ItemCollected, this);
}
private void OnDestroy()
{
eventMediator?.Unsubscribe(GameEventType.EnemyKilled, this);
eventMediator?.Unsubscribe(GameEventType.ItemCollected, this);
}
public void OnEvent(GameEventType eventType, object sender, object eventData)
{
switch (eventType)
{
case GameEventType.EnemyKilled:
Debug.Log("成就系統(tǒng): 敵人被擊殺");
// 更新?lián)魵⒊删?
break;
case GameEventType.ItemCollected:
Debug.Log("成就系統(tǒng): 物品被收集");
// 更新收集成就
break;
}
}
}
// 具體同事類 - 音頻管理器
public class AudioManager : MonoBehaviour, IGameEventSubscriber
{
private IGameEventMediator eventMediator;
private void Start()
{
eventMediator = FindObjectOfType<GameEventManager>();
eventMediator.Subscribe(GameEventType.PlayerDied, this);
eventMediator.Subscribe(GameEventType.LevelCompleted, this);
}
private void OnDestroy()
{
eventMediator?.Unsubscribe(GameEventType.PlayerDied, this);
eventMediator?.Unsubscribe(GameEventType.LevelCompleted, this);
}
public void OnEvent(GameEventType eventType, object sender, object eventData)
{
switch (eventType)
{
case GameEventType.PlayerDied:
Debug.Log("播放死亡音效");
// 播放死亡音效
break;
case GameEventType.LevelCompleted:
Debug.Log("播放關(guān)卡完成音效");
// 播放勝利音效
break;
}
}
}
示例3:AI協(xié)調(diào)系統(tǒng)
using UnityEngine;
using System.Collections.Generic;
// 中介者接口
public interface IAIMediator
{
void RegisterAI(AIEntity ai);
void UnregisterAI(AIEntity ai);
void SendMessage(AIEntity sender, string message);
}
// 具體中介者 - AI協(xié)調(diào)器
public class AICoordinator : MonoBehaviour, IAIMediator
{
private List<AIEntity> aiEntities = new List<AIEntity>();
// 注冊(cè)AI實(shí)體
public void RegisterAI(AIEntity ai)
{
if (!aiEntities.Contains(ai))
{
aiEntities.Add(ai);
}
}
// 注銷AI實(shí)體
public void UnregisterAI(AIEntity ai)
{
aiEntities.Remove(ai);
}
// 廣播消息
public void SendMessage(AIEntity sender, string message)
{
foreach (var ai in aiEntities)
{
if (ai != sender) // 不發(fā)送給自己
{
ai.ReceiveMessage(message);
}
}
}
}
// 同事類 - AI實(shí)體基類
public abstract class AIEntity : MonoBehaviour
{
protected IAIMediator mediator;
// 設(shè)置中介者
public void SetMediator(IAIMediator mediator)
{
this.mediator = mediator;
mediator.RegisterAI(this);
}
// 發(fā)送消息
protected void SendToOthers(string message)
{
mediator?.SendMessage(this, message);
}
// 接收消息
public abstract void ReceiveMessage(string message);
private void OnDestroy()
{
mediator?.UnregisterAI(this);
}
}
// 具體同事類 - 守衛(wèi)AI
public class GuardAI : AIEntity
{
private bool isAlerted = false;
private void Start()
{
// 在中介者中注冊(cè)
SetMediator(FindObjectOfType<AICoordinator>());
}
// 發(fā)現(xiàn)玩家
public void SpotPlayer()
{
Debug.Log("守衛(wèi)發(fā)現(xiàn)玩家!");
isAlerted = true;
SendToOthers("PlayerSpotted");
}
// 接收消息
public override void ReceiveMessage(string message)
{
if (message == "PlayerSpotted" && !isAlerted)
{
Debug.Log("守衛(wèi)收到警報(bào): 玩家被發(fā)現(xiàn)!");
isAlerted = true;
// 進(jìn)入警戒狀態(tài)
}
}
}
// 具體同事類 - 巡邏AI
public class PatrolAI : AIEntity
{
private bool isAlerted = false;
private void Start()
{
// 在中介者中注冊(cè)
SetMediator(FindObjectOfType<AICoordinator>());
}
// 發(fā)現(xiàn)玩家
public void SpotPlayer()
{
Debug.Log("巡邏AI發(fā)現(xiàn)玩家!");
isAlerted = true;
SendToOthers("PlayerSpotted");
}
// 接收消息
public override void ReceiveMessage(string message)
{
if (message == "PlayerSpotted" && !isAlerted)
{
Debug.Log("巡邏AI收到警報(bào): 玩家被發(fā)現(xiàn)!");
isAlerted = true;
// 改變巡邏路線
}
}
}
// 具體同事類 - 狙擊手AI
public class SniperAI : AIEntity
{
private bool isAlerted = false;
private void Start()
{
// 在中介者中注冊(cè)
SetMediator(FindObjectOfType<AICoordinator>());
}
// 接收消息
public override void ReceiveMessage(string message)
{
if (message == "PlayerSpotted" && !isAlerted)
{
Debug.Log("狙擊手收到警報(bào): 玩家被發(fā)現(xiàn)!準(zhǔn)備狙擊...");
isAlerted = true;
// 進(jìn)入狙擊位置
}
}
}
在Unity中的實(shí)現(xiàn)建議
- 使用ScriptableObject:可以將中介者實(shí)現(xiàn)為ScriptableObject,便于在編輯器中配置
- 與事件系統(tǒng)結(jié)合:Unity自身的EventSystem也可以看作是一種中介者模式的實(shí)現(xiàn)
- 考慮性能:對(duì)于高頻交互,注意中介者可能成為性能瓶頸
- 避免過(guò)度使用:不是所有對(duì)象交互都需要中介者,簡(jiǎn)單交互可以直接通信
- 分層設(shè)計(jì):可以為不同子系統(tǒng)設(shè)計(jì)不同的中介者,避免單個(gè)中介者過(guò)于復(fù)雜
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
c#中Empty()和DefalutIfEmpty()用法分析
這篇文章主要介紹了c#中Empty()和DefalutIfEmpty()用法,以實(shí)例形式分析了針對(duì)不同情況下Empty()和DefalutIfEmpty()用法區(qū)別,需要的朋友可以參考下2014-11-11
unity實(shí)現(xiàn)車方向盤轉(zhuǎn)動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了unity實(shí)現(xiàn)車方向盤轉(zhuǎn)動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
Unity shader實(shí)現(xiàn)移動(dòng)端模擬深度水效果
這篇文章主要為大家詳細(xì)介紹了Unity shader實(shí)現(xiàn)移動(dòng)端模擬深度水效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
C# WinForm控件對(duì)透明圖片重疊時(shí)出現(xiàn)圖片不透明的簡(jiǎn)單解決方法
這篇文章主要介紹了C# WinForm控件對(duì)透明圖片重疊時(shí)出現(xiàn)圖片不透明的簡(jiǎn)單解決方法,結(jié)合實(shí)例形式分析了WinForm圖片重疊后造成圖片不透明的原因與相應(yīng)的解決方法,需要的朋友可以參考下2016-06-06
C#設(shè)計(jì)模式之ChainOfResponsibility職責(zé)鏈模式解決真假美猴王問(wèn)題實(shí)例
這篇文章主要介紹了C#設(shè)計(jì)模式之ChainOfResponsibility職責(zé)鏈模式解決真假美猴王問(wèn)題,簡(jiǎn)單說(shuō)明了責(zé)任鏈模式的概念,并結(jié)合《西游記》中真假美猴王故事背景為實(shí)例分析了責(zé)任鏈模式的具體使用技巧,需要的朋友可以參考下2017-09-09
C#使用dir命令實(shí)現(xiàn)文件搜索功能示例
這篇文章主要介紹了C#使用dir命令實(shí)現(xiàn)文件搜索功能,結(jié)合具體實(shí)例形式分析了C#調(diào)用與使用cmd命令相關(guān)操作技巧,需要的朋友可以參考下2017-07-07

