设计模式-中介者模式
定义:用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互
使用场景:
对象与对象之间存在大量的关联关系,导致系统的结构变得很复杂,对象之间形成网状拓扑结构,一个对象发生变化,其它对象也需要相应的修改处理。
网状拓扑结构如下
使用中介者模式我们希望将对象之间的网状拓扑结构调整为星型拓扑结构
星型拓扑结构如下
中介者模式的类图结构如下
Mediator 抽象中介者
抽象中介者定义统一的接口,用于各同事之间的交互
ConcreteMediator 具体中介者
实现抽象类方法,它需要知道所有具体同事角色,通过协调各具体同事角色实现协作行为。
Colleague 抽象同事角色
定义同事类共同的行为接口,保存中介者对象
ConcreteColleague 具体同事角色
每个具体同事只知道自己的行为,而不了解其他同事类的情况,但是它们都认识中介者对象。
实例看上边星型拓扑结构图
公司内员工的报销流程,首先员工需要到财务申领报销单,填写报销单, 需要部门主管、CEO、CFO 签字,最后财务审批盖章通过。
公司员工那么多,每个人报销都要去找 部门主管、CEO、CFO签字,首先员工需要通过各种渠道找到这些领导们,然后领导们还得确认他们是公司的员工,再签字,领导们也会被一个一个陆续过来的员工打断当前工作,双方都很苦恼,于是公司决定以后所有的报销单 员工先填写,财务每周五收取所有员工的报销单,财务拿着所有的报销单到每个领导处统一签字,最后财务审批盖章同意报销申请。
代码实现如下
报销单,报销需要的单据,不属于中介者也不属于同事类
// 报销单
public class ReimbursementDocument
{
// 报销原因
public string reason;
// 员工姓名
public string name;
// 报销钱数
public float money;
// 签字
public List<string> signList = new List<string>();
// 盖章
public string stamp;
}
Mediator 抽象中介者
// 抽象中介者
public interface IMediator
{
// 报销
void ExpenseAccount();
// 添加员工
void AddColleague(IColleague colleague);
}
ConcreteMediator 具体中介者
// 财务:具体中介者
public class Finance : Colleague, IMediator
{
// 具体中介者需要知道具体的同事类
private CEO _ceo;
private CFO _cfo;
private DepartmentManager _departmentManager;
private List<IColleague> colleagueList = new List<IColleague>();
public Finance(string name) : base(name)
{
}
// 添加 CEO 具体的同事类
public void SetCEO(CEO ceo)
{
_ceo = ceo;
}
// 添加 CFO 具体的同事类
public void SetCFO(CFO cfo)
{
_cfo = cfo;
}
// 添加部门主管 具体的同事类
public void SetDM(DepartmentManager dp)
{
_departmentManager = dp;
}
// 添加同事
public void AddColleague(IColleague colleague)
{
colleagueList.Add(colleague);
}
// 报销
public void ExpenseAccount()
{
foreach(var colleague in colleagueList)
{
ReimbursementDocument rd = colleague.GetRD();
if (null == rd)
{
continue;
}
// 部门主管签字
_departmentManager.Sign(rd);
// CEO 签字
_ceo.Sign(rd);
// CFO 审核
_cfo.Check(rd);
rd.stamp = "财务盖章";
string msg = string.Format("{0}_{1}_{2}_{3}、{4}、{5}_{6} \n", rd.name, rd.reason, rd.money, rd.signList[0], rd.signList[1], rd.signList[2], rd.stamp);
Console.WriteLine(msg);
}
}
}
Colleague 抽象同事角色
// 抽象同事
public abstract class IColleague
{
private string _name;
public IColleague(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
private IMediator _imediator;
void AddMediator(IMediator mediator)
{
_imediator = mediator;
}
// 报销单
public virtual ReimbursementDocument GetRD()
{
return null;
}
}
ConcreteColleague 具体同事角色
// 员工:具体同事
public class Colleague : IColleague
{
public Colleague(string name) : base(name)
{
}
// 获取报销单
public override ReimbursementDocument GetRD()
{
ReimbursementDocument reimbursementDocument = new ReimbursementDocument();
reimbursementDocument.reason = "打车报销";
reimbursementDocument.name = Name;
reimbursementDocument.money = 100;
return reimbursementDocument;
}
}
// CEO:具体同事
public class CEO : IColleague
{
public CEO(string name) : base(name)
{
}
public void Sign(ReimbursementDocument rd)
{
rd.signList.Add("CEO 签字");
}
}
// CFO:具体同事
public class CFO : IColleague
{
public CFO(string name) : base(name)
{
}
// 审核
public void Check(ReimbursementDocument rd)
{
rd.signList.Add("CFO 审核通过了,签字");
}
}
// 部门主管:具体同事
public class DepartmentManager : IColleague
{
public DepartmentManager(string name) : base(name)
{
}
public void Sign(ReimbursementDocument rd)
{
rd.signList.Add("部门主管签字");
}
}
调用如下
public class Client
{
public Client()
{
Colleague colleague1 = new Colleague("张三");
Colleague colleague2 = new Colleague("李四");
CEO ceo = new CEO("赵五");
CFO cfo = new CFO("冯七");
DepartmentManager dm = new DepartmentManager("刘八");
IMediator mediator = new Finance("周九");
mediator.AddColleague(colleague1);
mediator.AddColleague(colleague2);
mediator.AddColleague(ceo);
mediator.AddColleague(cfo);
mediator.AddColleague(dm);
(mediator as Finance).SetCEO(ceo);
(mediator as Finance).SetCFO(cfo);
(mediator as Finance).SetDM(dm);
mediator.ExpenseAccount();
}
}
运行结果如下
优点:
(1)减少了类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,降低了类间的耦合
缺点:
(1)中介者或膨胀的很大,而且逻辑复杂,原本多个类直接的相互依赖关系转换为中介者和同事类的依赖关系,同事类越多,中介者的逻辑就越复杂