星辰.Net技术社区论坛

首页 » .NET » 设计模式GOF » 组件设计实战--组件之间的关系(Event、依赖倒置、Bridge)
star65225692 - 2008-6-14 14:09:00
一个组件与另一个组件之间的关系可以通过三种方式建立起来:事件、依赖倒置、Bridge。现在我们只考虑单向依赖的关系,即信息提供者和信息消费者。事件是一种松耦合的信息发布方式,事件发布者(信息提供者)不需要关心事件预定者(即信息消费者)的任何信息,但是事件预定者需要依赖事件发布者;依赖倒置则反转了这种关系,在依赖倒置的方式中,信息提供者依赖信息消费者(你也许对这句话觉得奇怪,后面的例子会说明),而信息消费者不需要了解信息提供者的任何信息;所谓Bridge,就是一个中介者模式,在采用这种设计时,信息发布者和信息提供者是完全相互独立的,互不依赖,它们之间通过Bridge桥接起来。qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    那么在设计组建之间的关系时到底该选择那种方式,则需要依据实际情况而定。假设,组件A是信息提供者,而组件B是信息消费者。可以有以下几种情况:qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
(1)A发布事件,B包含A的引用,然后B预定A的事件。(事件方式)qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
(2)B接口中提供接收信息的方法,A包含B的引用,在适当时候A调用B的接收信息的方法。(依赖倒置方式)qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
(3)A发布事件,B接口中提供接收信息的方法,通过Bridge将A、B联系起来。(Bridge方式)qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    下面举个实际的例子,在我们的应用中,有个功能服务管理器IServiceManager(信息提供者),功能服务可以在运行的时候变化,这个变化可以被IServiceManager检测到,而显示功能服务名称的IServiceDisplayer(信息消费者)也需要在功能服务变化的时候,将显示作必要的改变。如果按照“事件”方式,应该如下设计:qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    public interface IServiceManagerqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
event CbServiceAdded ServiceAdded ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
   
public delegate void CbServiceAdded(string serviceName) ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
   
public interface IServiceDisplayerqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        IServiceManager ServiceManager ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    }
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
按照“依赖倒置”方式设计如下:qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    public interface IServiceManagerqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        IServiceDisplayer ServiceDisplayer{
set ;}qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
   
public interface IServiceDisplayerqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
void AddService(string serviceName) ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    }
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
按照“Bridge”方式设计如下:qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    public interface IServiceManagerqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
event CbServiceAdded ServiceAdded ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
   
public delegate void CbServiceAdded(string serviceName) ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
   
public interface IServiceDisplayerqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
void AddService(string serviceName) ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
   
public interface IServiceBridgeqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        IServiceManager  ServiceManager{
set ;}qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        IServiceDisplayer ServiceDisplayer{
set ;}qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
void Initialize();qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
   
public class ServiceBridge :IServiceBridgeqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
private IServiceManager  serviceManager = null ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
private IServiceDisplayer serviceDisplayer = null ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
#region IServiceBridge 成员qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
public void Initialize()qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
           
this.serviceManager.ServiceAdded += new CbServiceAdded(serviceManager_ServiceAdded);qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
public IServiceManager ServiceManagerqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
           
setqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
            {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
               
this.serviceManager = value ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
            }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
public IServiceDisplayer ServiceDisplayerqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
           
setqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
            {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
               
this.serviceDisplayer = value ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
            }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
#endregionqÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
       
private void serviceManager_ServiceAdded(string serviceName)qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        {qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
           
this.serviceDisplayer.AddService(serviceName) ;qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
        }qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    }
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
    三种方式都是可行的,但是在不同的应用情况下,不同的方式导致应用程序中组件之间不同的依赖复杂度,并对整个系统的结构的清晰度产生深刻的影响。那么,原则是什么?qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
(1)通常情况下,采用“事件”方式。qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
(2)如果使用“事件”方式时遇到这样的情况:IServiceDisplayer预定的IServiceManager的那部分事件的预定者只有IServiceDisplayer,而不会有其它组件预定这部分事件,则可以考虑将这些事件从IServiceManager中移除,转而采用“依赖倒置”方式。这样做的好处是,大大减少了IServiceManager需要发布的事件的数量。qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
(3)如果IServiceDisplayer所需的信息不仅仅来自IServiceManager,还来自许多其它组件,则采用第三种方式。qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
(4)要谨慎使用“依赖倒置”方式,特别是当IServiceManager不需要从IServiceDisplayer获取任何信息时,第二种方式会导致IServiceManager对IServiceManager的依赖,而这个依赖本来是不必要的。qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
(5)当一个(或多个)信息接受者需要从众多的信息发布者获取事件信息时,使用第三种方式是推荐的选择。qÞT–fwww.netcsharp.cnñáˆs}µÚGÞÝ
1
查看完整版本: 组件设计实战--组件之间的关系(Event、依赖倒置、Bridge)