zoukankan      html  css  js  c++  java
  • 写给自己看的小设计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。

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

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

     
     
     
  • 相关阅读:
    2.5 进程控制之wait函数
    2.4 进程控制之僵尸进程和孤儿进程
    九、IIC驱动原理分析
    2.3 进程控制之exec函数族
    8.2 USB键盘驱动编写和测试
    1. tty终端接收数据原理
    第3章 MySQL常用增,删,改,查,用户授权,备份,等操作
    Linux命令总结--top命令
    Linux--LNMP
    Linux命令总结-ps pstree pgrep命令
  • 原文地址:https://www.cnblogs.com/dxy1982/p/4520407.html
Copyright © 2011-2022 走看看