`
callwangxiang
  • 浏览: 3309 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

《模式——工程化实现及扩展》(设计模式C# 版)《中介者模式》——“自我检验" 参考答案

阅读更多
转自:《模式——工程化实现及扩展》(设计模式C# 版)
http://www.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 ; }
    
#endregion

    
public   override   string  ToString()
    {
        
return   string .Format( " \n[{0}]\n------------------\n{1}\n({2})\n " , 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 archived

1  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 archived

1  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 ; }
        
public   string  SourceEventName {  get set ; }
        
public   string  TargetHandlerMethodName {  get set ; }

        
public   override   bool  Equals( object  obj)
        {
            
if  (obj  ==   null throw   new  ArgumentNullException( " obj " );
            var target 
=  (ConfigItem)obj;
            
return
                SourceType 
==  target.SourceType  &&
                TargetType 
==  target.TargetType  &&
                
string .Equals(SourceEventName, target.SourceEventName)  &&
                
string .Equals(TargetHandlerMethodName, target.TargetHandlerMethodName);
        }
    }

    IList
< ConfigItem >  config  =   new  List < ConfigItem > ();

    
public  EventMediatorBuilder AddConfig(Type sourceType, Type targetType,  string  sourceEventName,  string  targetHandlerMethodName)
    {
        
if  (sourceType  ==   null throw   new  ArgumentNullException( " sourceType " );
        
if  (targetType  ==   null throw   new  ArgumentNullException( " targetType " );
        
if  ( string .IsNullOrEmpty(sourceEventName))  throw   new  ArgumentNullException( " sourceEventName " );
        
if  ( string .IsNullOrEmpty(targetHandlerMethodName))  throw   new  ArgumentNullException( " targetHandlerMethodName " );

        
if  (sourceType.GetEvent(sourceEventName)  ==   null throw   new  NotSupportedException(sourceEventName);
        var item 
=   new  ConfigItem()
        {
            SourceType 
=  sourceType,
            TargetType 
=  targetType,
            SourceEventName 
=  sourceEventName,
            TargetHandlerMethodName 
=  targetHandlerMethodName
        };
        
if  ( ! config.Contains(item))
            config.Add(item);

        
return   this ;
    }

    
public  EventMediatorBuilder BuildAUpColleagues( params   object [] colleagues)
    {
        
if  (colleagues  ==   null throw   new  ArgumentNullException( " colleagues " );
        
if  (config.Count()  ==   0 return   this ;        //   没有通信关系配置项
         if  (colleagues.Count()  ==   1 return   this ;     //   没有需要配置的关联对象组
        colleagues.ToList().ForEach(x  =>  {  if  (x  ==   null throw   new  ArgumentNullException(); });

        
/// /  限制:不支持一类对象的某个实例同时向另一类对象多个实例的通知
         // if (colleagues.GroupBy(x => x.GetType()).Count() != colleagues.Count())
        
//     throw new NotSupportedException();

        
foreach  (var item  in  config)
        {
            var sources 
=  colleagues.Where(x  =>  x.GetType()  ==  item.SourceType);
            
if  ((sources  ==   null ||  (sources.Count()  ==   0 ))
                
continue ;
            var targets 
=  colleagues.Where(x  =>  x.GetType()  ==  item.TargetType);
            
if  ((targets  ==   null ||  (targets.Count()  ==   0 ))
                
continue ;
            var eventInfo 
=  item.SourceType.GetEvent(item.SourceEventName);
            
if  (eventInfo  ==   null )
                
continue ;
            var methodInfo 
=  item.TargetType.GetMethod(item.TargetHandlerMethodName, BindingFlags.Public  |  BindingFlags.Instance);
            
if  (methodInfo  ==   null )
                
continue ;

            
//   绑定事件响应关系
             foreach  (var source  in  sources)
                
foreach  (var target  in  targets)
                    eventInfo.AddEventHandler(source, Delegate.CreateDelegate(eventInfo.EventHandlerType, target, methodInfo));
        }

        
return   this ;
    }
}

 

实现和单元测试验证

 

using  System;
using  System.Diagnostics;
using  System.Collections.Generic;
using  System.Linq;
using  System.Reflection;
using  Microsoft.VisualStudio.TestTools.UnitTesting;
namespace  MarvellousWorks.PracticalPattern.Mediator.Tests.Exercise
{
    [TestClass]
    
public   class  DocumentWorkflowMediatorFixture
    {
        Scenario1.A a1;
        Scenario1.B b1;
        Scenario1.C c1;
        Scenario2.A a2;
        Scenario2.B b2;
        Scenario2.C c2;
        Scenario2.D d2;

        EventMediatorBuilder scenario1Builder;
        EventMediatorBuilder scenario2Builder;

        
///   <summary>
        
///  配置不同协调关系
        
///  实际项目中可以采用本章介绍的基于配置文件的定义方式
        
///   </summary>
        [TestInitialize]
        
public   void  Initialize()
        {
            a1 
=   new  Scenario1.A();
            b1 
=   new  Scenario1.B();
            c1 
=   new  Scenario1.C();
            a2 
=   new  Scenario2.A();
            b2 
=   new  Scenario2.B();
            c2 
=   new  Scenario2.C();
            d2 
=   new  Scenario2.D();

            scenario1Builder 
=   new  EventMediatorBuilder()
                
//   1.    A部门拟稿后将文件报B部门审核
                .AddConfig( typeof (Scenario1.A),  typeof (Scenario1.B),  " WriteDocumentFinishedHandler " " OnReceiveFileToReview " )
                
//   2.    B部门对于文件审核后,确认文件体例没有缺项后就通知C部门发布
                .AddConfig( typeof (Scenario1.B),  typeof (Scenario1.C),  " ReviewDocumentSucceedHandler " " OnReceiveFileToPublish " )
                
//   3.    如果B部门发现文件体例有缺项时,将文件返回给A部门重新修改
                .AddConfig( typeof (Scenario1.B),  typeof (Scenario1.A),  " ReviewDocumentFailedHandler " " OnReviewFailed " )
                
//   4.    C部门在接到B部门传来的文件时,先再发布,然后对其归档
                .AddConfig( typeof (Scenario1.C),  typeof (Scenario1.C),  " DocumentPublishedHandler " " OnReceiveFileToArchive " );


            scenario2Builder 
=   new  EventMediatorBuilder()
                .AddConfig(
typeof (Scenario2.A),  typeof (Scenario2.B),  " WriteDocumentFinishedHandler " " OnReceiveFileToReview " )
                .AddConfig(
typeof (Scenario2.A),  typeof (Scenario2.D),  " WriteDocumentFinishedHandler " " OnReceiveFileToArchive " )
                .AddConfig(
typeof (Scenario2.B),  typeof (Scenario2.A),  " ReviewDocumentFailedHandler " " OnReviewFailed " )
                .AddConfig(
typeof (Scenario2.B),  typeof (Scenario2.D),  " ReviewDocumentFailedHandler " " OnReceiveFileToArchive " )
                .AddConfig(
typeof (Scenario2.B),  typeof (Scenario2.C),  " ReviewDocumentSucceedHandler " " OnReceiveFileToPublish " )
                .AddConfig(
typeof (Scenario2.C),  typeof (Scenario2.D),  " DocumentPublishedHandler " " OnReceiveFileToArchive " );

        }

        
///   <summary>
        
///  测试通过Event Mediator Builder构造现有业务流程下的协作关系
        
///   </summary>
        [TestMethod]
        
public   void  TestScenario1()
        {
            
//   通过Event Mediator以及配置信息建立三个部门Colleague间的协作关系
            
//   所有协调关系统一剥离到作为Mediator的.NET事件机制上
            scenario1Builder.BuildAUpColleagues(a1, b1, c1);

            
//   成功的路径
            Trace.WriteLine( " Succeed path " );
            a1.Write(
" a " " b " " c " );

            
//   失败的路径
            Trace.WriteLine( " \n\nFailed path " );
            a1.Write(
" a " "" "" );

            
//   修正错误的内容,重新执行流程
            Trace.WriteLine( " Modified after review failed path " );
            a1.Write(
" a " " b " " c " );
        }

        
///   <summary>
        
///  测试通过Event Mediator Builder构造管理层期望的未来业务流程下的协作关系
        
///   </summary>
        [TestMethod]
        
public   void  TestScenario2()
        {
            
//   通过Event Mediator以及配置信息建立三个部门Colleague间的协作关系
            
//   所有协调关系统一剥离到作为Mediator的.NET事件机制上
            scenario2Builder.BuildAUpColleagues(a2, b2, c2, d2);

            
//   成功的路径
            Trace.WriteLine( " Succeed path " );
            a2.Write(
" a " " b " " c " );

            
//   失败的路径
            Trace.WriteLine( " \n\nFailed path " );
            a2.Write(
" a " "" "" );

            
//   修正错误的内容,重新执行流程
            Trace.WriteLine( " Modified after review failed path " );
            a2.Write(
" a " " b " " c " );
        }
    }
}

 

 

备注1:现有情景下的A、B、C类型定义

 

namespace  Scenario1
{
    
class  A : Department
    {
        
public   event  EventHandler < DocumentEventArgs >  WriteDocumentFinishedHandler;

        
public   void  Write( string  subject,  string  body,  string  comment)
        {
            
if  (Document  ==   null throw   new  NullReferenceException( " Document " );
            Trace.WriteLine(
" A begin write " );
            Document.Subject 
=  subject;
            Document.Body 
=  body;
            Document.Comment 
=  comment;
            Trace.WriteLine(
" A write finished " );
            Trace.WriteLine(Document);

            
if (WriteDocumentFinishedHandler  !=   null )
                WriteDocumentFinishedHandler(
分享到:
评论

相关推荐

    设计模式:基于C#的工程化实现及扩展.pdf

    设计模式:基于C#的工程化实现及扩展

    设计模式:基于C#的工程化实现及扩展 王翔

    690页完整的《设计模式:基于C#的工程化实现及扩展 》王翔著作 pdf版

    设计模式——基于 C#的工程化实现及扩展(部分章节)

    ### 设计模式——基于C#的工程化实现及扩展 #### 第一部分:预备知识——发掘用C#语言进行面向对象化设计的潜力 ##### 第1章 重新研读C#语言 **1.1 说明** 本章旨在帮助读者更好地理解和掌握C#语言的核心特性...

    设计模式 基于C#的工程化实现及扩展 王翔 pdf

    《设计模式:基于C#的工程化实现及扩展》是由王翔编著的一本深入探讨设计模式在C#编程中的应用的专业书籍。这本书的核心在于如何将经典的23种设计模式有效地融入到C#的工程实践中,同时探讨了如何对这些模式进行扩展...

    《设计模式--基于C#的工程化实现及扩展》.(王翔)_(0601).rar

    《设计模式--基于C#的工程化实现及扩展》是一本深入探讨软件设计模式的书籍,作者王翔通过C#语言来阐述各种设计模式的工程化应用和拓展。设计模式是软件开发中的一种最佳实践,它总结了在特定场景下为解决常见问题而...

    设计模式——基于C#的工程化实现及扩展

    面向对象设计模式,也就是本书简称的“设计模式”,是软件实际...模式的主要价值在于它们是以往经验的浓缩,尤其在我们建立复杂系统的时候,借鉴个采用模式可以让我们少走弯路,其设计比较灵活并且具有不错的扩展性。

    《设计模式--基于C#的工程化实现及扩展》.(王翔).rar.rar

    《设计模式--基于C#的工程化实现及扩展》是一本深入探讨软件设计模式的书籍,作者为王翔。本书的核心目标是通过C#语言,系统地介绍和讲解设计模式在实际工程中的应用与拓展。设计模式是软件开发中经过实践验证的、可...

    《设计模式--基于C#的工程化实现及扩展》.(王翔).rar_0517

    《设计模式--基于C#的工程化实现及扩展》是一本深入探讨软件设计模式的书籍,作者王翔通过C#语言来阐述各种设计模式的工程化应用和拓展。设计模式是软件开发中的一种最佳实践,它总结了在解决特定问题时,经过时间和...

    设计模式之美——教你写出高质量代码

    设计模式是软件工程中的一种最佳实践,它是在特定上下文中解决常见问题的经验总结。"设计模式之美——教你写出高质量代码"这个主题旨在帮助开发者更好地理解和应用设计模式,从而提升代码的质量和可维护性。设计模式...

    设计模式源码.zip

    最后,"设计模式——基于C#的工程化实现及扩展_示例说明.txt"文件提供了对源码的解释和应用场景的描述,这对于初学者来说是极其宝贵的资源。它可以帮助你理解每个模式的意图、适用场景以及如何在C#代码中正确地引入...

    C#经典设计模式及代码示例

    《C#经典设计模式及代码示例》是针对C#开发者深入理解并应用设计模式的一份宝贵资源。设计模式是软件工程中经过实践验证的、解决常见问题的有效模板,能够帮助程序员提高代码的可读性、可维护性和复用性。这本书结合...

    设计模式:基于C#的工程化实现及扩展

    介绍软件编程中的设计思想,文中实例均基于C#,适合于有一定基础的编程人员。

    设计模式-基于C#的工程化实现及扩展.part3

    前26章!前26章!前26章!前26章!前26章!前26章!前26章!

    设计模式-基于C#的工程化实现及扩展.part6

    前26章!前26章!前26章!前26章!前26章!前26章!

    设计模式-基于C#的工程化实现及扩展.part4

    前26章!前26章!前26章!前26章!前26章!前26章!

    23种设计模式之C#版本.pdf

    在本文中,将详细探讨23种设计模式中的两种——单件模式(Singleton Pattern)和抽象工厂模式(Abstract Factory Pattern),并以C#语言为例来阐述其在实际开发中的应用和实现。 ### 单件模式(Singleton Pattern)...

    C#设计模式(英文版)

    《C#设计模式(英文版)》是一本深入探讨C#编程中常用设计模式的专业书籍。设计模式是软件工程中的重要概念,它们是解决常见问题的成熟、可重用的解决方案,可以提升代码的可读性、可维护性和扩展性。这本书通过英文版...

    设计模式——命令模式

    命令模式是一种行为设计模式,它将请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。在软件工程中,这种模式常用于解耦发出命令的对象(调用者)与...

    设计模式 C# 版

    本篇文档将重点介绍几种在C#实现的设计模式,包括中介者模式、备忘录模式、观察者模式、策略模式和访问者模式。 首先,我们来看中介者模式(Mediator Pattern)。中介者模式用于减少类之间的通信复杂性。在没有中介...

Global site tag (gtag.js) - Google Analytics