《模式——工程化实现及扩展》(设计模式C# 版)《中介者模式》——“自我检验 参考答案
cnblogs.com/callwangxiang/
MarvellousWorks公司有A、B、C三个部门负责文件的拟稿、审批和备案,现有的流程如下:
1. A部门拟稿后将文件报B部门审核
2. B部门对于文件审核后,确认文件体例没有缺项后就通知C部门发布
3. 如果B部门发现文件体例有缺项时,将文件返回给A部门重新修改
4. C部门在接到B部门传来的文件时,先再发布,然后对其归档
不过,MarvellousWorks的管理层为了加强部门间文件流转的管理,正在酝酿修改工作流程:
1、 增加D部门专门负责归档,C部门将归档职责划入D部门后只负责发布文件
2、 C部门发布文件后也须先在D部门归档
3、 A、B部门间所有往复流转的中间文件也都报给D部门归档
请采用本章介绍的中介者模式及其扩展处理,将文件的流转调度过程从A、B、C、D各对象的职责中独立出来,并用单元测试验证不同的流转过程。
文件对象的定义
class Document
{
#region essential fields
public string Subject { get; set; }
public string Body { get; set; }
#endregion#region optional fields
public string Comment { get; set; }
#endregionpublic override string ToString()
{
return string.Format(" [{0}] ------------------ {1} ({2}) ", Subject, Body, Comment);
}
}
参考答案
分析第一步
上述A、B、C、D部门间的协作关系比较复杂,而且预期很快会变化,但协作的中间内容很简单——都是文件,所以采用事件方式,由.NET Framework自己的事件机制作为中介者相对很简单,而且类型间的依赖关系全都推给.NET Framework,为以后扩展更多参与方的协作关系提供便利。
据此,我们定义A、B、C、D时全部采用事件作为提供给外中介者协调响应关系的入口。
增加如下类型
class DocumentEventArgs : EventArgs
{
Document document;
public DocumentEventArgs(Document document)
{
this.document = document;
}
public Document Document{get{ return document;}}
}abstract class Department
{
protected Document document = new Document();
public Document Document
{
get{ return document;}
protected set{ document = value;}
}
}
分析第二步
如果直接通过事件重载操作符 +=和-=建立各Colleague的响应关系,需要重复编写代码,而且不能在系统上线后将这个工作交给管理员维护。
因此,考虑参考前面的Builder模式,增加一个基于配置动态维护维护事件响应关系的对象。
实现和单元测试验证
1、验证“分析第一步”的设想
/// <summary>
/// 测试手工定义事件中介者的交互关系
/// </summary>
[TestMethod]
public void TestManualDefineEventMediatorInSucceedBranch()
{
// 用事件配置松散的响应关系
a1.WriteDocumentFinishedHandler += b1.OnReceiveFileToReview;
b1.ReviewDocumentFailedHandler += a1.OnReviewFailed;
b1.ReviewDocumentSucceedHandler += c1.OnReceiveFileToPublish;
b1.ReviewDocumentSucceedHandler += c1.OnReceiveFileToArchive;// 成功的路径
a1.Write("a", "b", "c");// 验证修订后的内容曾经流转给了B
Assert.AreEqual<string>("a", b1.Document.Subject);
Assert.AreEqual<string>("b", b1.Document.Body);
Assert.AreEqual<string>("c", b1.Document.Comment);// 验证修订后的内容也曾经流转给了C
Assert.AreEqual<string>("a", c1.Document.Subject);
Assert.AreEqual<string>("b", c1.Document.Body);
Assert.AreEqual<string>("c", c1.Document.Comment);
}
Output窗口------ Test started: Assembly: Mediator.Tests.dll ------
A begin write
A write finished[a]
------------------
b
(c)B received doc from A to review
B begin review
B review succeed
C received doc to publish from B
C published
C received doc to archive from B
C archived1 passed, 0 failed, 0 skipped, took 0.50 seconds (MSTest 10.0).
/// <summary>
/// 测试手工定义事件中介者的交互关系
/// </summary>
[TestMethod]
public void TestManualDefineEventMediatorInFailedBranch()
{
// 用事件配置松散的响应关系
a1.WriteDocumentFinishedHandler += b1.OnReceiveFileToReview;
b1.ReviewDocumentFailedHandler += a1.OnReviewFailed;
b1.ReviewDocumentSucceedHandler += c1.OnReceiveFileToPublish;
b1.ReviewDocumentSucceedHandler += c1.OnReceiveFileToArchive;// 失败的路径
a1.Write("a", "", "");// 验证确实文档曾经流转给了B
Assert.AreEqual<string>("a", b1.Document.Subject);
Assert.AreEqual<string>("", b1.Document.Body);
Assert.AreEqual<string>("", b1.Document.Comment);// 验证文档并没有流转给C
Assert.IsNull(c1.Document.Subject);
Assert.IsNull(c1.Document.Body);
Assert.IsNull(c1.Document.Comment);// 修正错误的内容,重新执行流程
a1.Write("a", "b", "c");// 验证修订后的内容曾经流转给了B
Assert.AreEqual<string>("a", b1.Document.Subject);
Assert.AreEqual<string>("b", b1.Document.Body);
Assert.AreEqual<string>("c", b1.Document.Comment);// 验证修订后的内容也曾经流转给了C
Assert.AreEqual<string>("a", c1.Document.Subject);
Assert.AreEqual<string>("b", c1.Document.Body);
Assert.AreEqual<string>("c", c1.Document.Comment);
}
Output窗口
------ Test started: Assembly: Mediator.Tests.dll ------
A begin write
A write finished[a]
------------------()
B received doc from A to review
B begin review
B review failed
A received doc review failed from B
A begin write
A write finished[a]
------------------
b
(c)B received doc from A to review
B begin review
B review succeed
C received doc to publish from B
C published
C received doc to archive from B
C archived1 passed, 0 failed, 0 skipped, took 3.64 seconds (MSTest 10.0).
2、验证“分析第二部” 的设想
定义管理基于事件的中介关系Builder
class EventMediatorBuilder
{
class ConfigItem
{
public Type SourceType { get; set; }
public Type TargetType { get; set; }
补充:综合编程 , 其他综合 ,