转载

写给自己看的小设计7 - 对象设计过程之对象交互

对象创建完了以后,就是互相协作完成系统的功能。对象的协作方式通常有如下方式:

直接引用,互通有无

这种方式最为自然,最为直接,最为简单,也是通常情况下的首选。不管是传参数,还是直接创建后直接使用对象的方法,都是属于这种情况:

public class ComponentB {  public void Run(ComponentA componentA) { componentA.Say(); } }

依靠中介通信

当对象之间的交互复杂起来以后,直接的通信可能耦合度就太高了,这个时候要靠辅助对象来间接的传递信息,很多的设计模式其实都是该思想的衍生物,比如中介者模式,代理模式,外观模式等。

这里看一个UI层的例子:程序的界面上有3个对象,分别是Panel,Timeline,Scrollbar;这些对象之间分属不同的层次结构,但是它们之间需要互相操作,比如Scrollbar动的时候,需要修改Timeline上的一些小控件,而且需要操作Panel的一些控件,操作Timeline上的内容的时候,需要检查是否需要滚动Scrollbar,是否需要操作Panel,总之就是这3个对象的其中一个动的话,另外两个都要有些操作需要进行。

针对这个交互的问题,我大概有3种想法:

第一种:3个对象之间互相引用,当需要的时候就直接调用对方的方法。

比如Panel类的伪代码就可能如下所示:

class Panel {   private Timeline m_timeline;   private Scrollbar m_scrollbar;     public void Action()   {     DoSomething();     m_timeline.M1();     m_scrollbar.M2();   }   }

第二种:能否尝试使用事件来回调自己的方法。

在脑海中就是那么一想,我决定放弃这个想法。

第三种:创建一个中介对象,所有交互的代码都放到这个中介中。

中介者和Panel的伪代码如下:

class Mediator {   private Timeline m_timeline;   private Scrollbar m_scrollbar;   private Panel m_panel;     public void Initialize(Timeline timeline, Scrollbar scrollbar, Panel panel)   {     m_timeline = timeline;     m_scrollbar = scrollbar;     m_panel = panel;   }     public void PanelAction()   {     m_timeline.M1();     m_scrollbar.M2();   }     public void ScrollbarAction()   {     m_timeline.M1();     m_panel.M3();   }     public void TimelineAction()   {     m_scrollbar.M2();     m_panel.M3();   } }   class Panel {   Mediator m_mediator;   public void Action()   {     DoSomething();     m_mediator.PanelAction();   } }

如果说前两种实现是形成了3个对象之间的网状图的话,那么第三种实现其实是多加了中介者对象,4个对象形成了以中介者为中心的星状图。

我实际采用了第三种实现来简化对象之间的交互关系。 我这里并不想说第三种一定比前两种好,如果没有变化存在,只要是让系统正常工作的代码其实都是好代码。我总是认为, 并不是任何时候状态模式就比分支语句更合适一个对象

其实除了依靠进程内对象通信外,依靠程序外的媒介通信也属于这种情况,比如利用共享内存,Socket,文件系统中的文件,第三方消息队列(如MSMQ),分布式中间件等通信。

使用事件通信

当对象之间通信方式同质化严重(工作方式基本类似,交互的方式也类似),特别是1对多的通信,而且交互对象数量较多,类型未知时,事件,或者说是观察者模式,或者说是发布订阅模式就可以使用起来了。

让我再来回忆一下前面使用过的一个例子:

public class Program {  static void Main(string[] args)  {   User user = new User();   View ui = new View(user);   user.Name = "Hello";  } }   delegate void OnNameChange(string name); class View {  public View(User user)  {   user.onNameChanged += user_onNameChanged;  }    void user_onNameChanged(string name)  {   Console.WriteLine(name);  } }   class User {  private string m_name;  public string Name  {   get { return m_name; }   set   {    m_name = value;    onNameChanged(m_name);   }  }  public event OnNameChange onNameChanged; }

交互即耦合

其实对象交互的方式,本质上就是描述了对象耦合的方式 。强耦合的关系一旦面临变化,一般会引起较大范围的改动。众多模式的出现都是为了给对象解耦。

对象之间的交互产生了对象之间的耦合,这是自然而有效的,对象之间就是要通过交互而形成流程,进而完成整个业务。除了上面这些描述的耦合方式,其实还有一个耦合方式更加紧密,那就是继承。

看一段简单的代码:

class Base {} class Derived : Base {}

这样简单的代码,其实就是形成了一个相当紧密的耦合:Base的任何修改都会毫无保留的传递给Derived。

同时,给予这样的一个分析,我们可以解释一个常识:为什么基类要尽量的抽象,不完成特别具体的细节。这么做就是为了 尽量维护基类的稳定,让基类尽量不变化

总结来说, 对象交互的常用方式就是:"继承+组合(直接引用)+中介+事件",而这些方式的耦合级别也是基本按这个顺序越来越弱

正文到此结束
Loading...