OO设计原则总结》一文中我提出了一个问题:如何更好的使用这些原则?怎样在实践中遵守这些原则,使用三种视角思考问题就是答案之一;

     

    本文内容包括:

    1.为什么我们过早的纠缠于细节?问题的本质是什么?

    2.救命稻草--Martin Fowler的三层视角理论

    3.三层视角--回头再说OO设计原则

     

  1. 为什么我们过早的纠缠于细节?问题的本质是什么?
             做设计时过早的关注细节几乎是多数程序员的泥沼,也是我自己的顽疾。就像我刚开始工作不久要做一个自动更新的系统,设计会议上开发组老大定了使用FTP协议完成,你知道我脑袋里面想的是什么?--Indy组件好像不支持中文”…...

          过早的关注细节,大体上可能有两种原因:1.经验丰富,举一反三,纲举目张,各种技术玄妙如数家珍 2.没有什么经验,只知道点技术细节,难以跳出思维桎梏;我知道我是后者,以前是现在也是。

           人是有惰性的,人们习惯性的做自己熟练精通的事情。所以做设计的时候,当对大框架缺少把握能力的时候,潜意识里我更愿意去思考那些细节。这是在偷懒,所有的技术细节、问题都是没有疑问的(我们不是做科研),或者是有疑问你可以很容易获得解答无论是开发文档还是在社区。细节的解决方案总是显而易见,但并非肯定是最好的入手点。

           有时候我真的要做设计了,我想要避免陷入“细节泥沼”可是我还是无意中把细节扯进来,这是为什么?剖析自己,我知道这是因为我的思考是平铺的,是没有层次的,所有的问题搅在一起,做设计的时候难免拖泥带水,泥沙俱下。

           思考没有层次这就是问题本质所在,我要做好设计,而思维方式上的缺陷成为我的命门所在,我该怎么办?说实话我一直在走弯路,而且不知道现在的这条路是否对头。
            “善良的人在追求的中纵然迷茫,却终将意识到有一条正途.-----《浮士德》
     

  2. 救命稻草--Martin Fowler的三层视角理论

         Martin Fowler在他的著作 UML Distilled》中提到了三层视角(perspective):概念视角,规约视角,实现视角。

    使用三种视角看软件开发,我们可以得到这样的描述:

    概念视角:呈现所研究领域中的各种概念,得出概念模型的时候应该尽量少德或者不考虑它的实现,这个视角要回答的问题是:软件要负责什么?是策略性的结论

    规约视角:我们现在考虑的是软件,但是我们关注的是软件的接口而不是实现。规约视角要回答的问题是:怎么使用软件?这个层次关注的是软件各部分的交流。

    实现:这时我们考虑的是代码本身但是许多方面我们使用规约视角可能会更好,软件在规约层交流在实现层执行。

     

    视角帮助我们将问题划分层次,隔离

            从上面的描述我们很明显得看到“软件开发”所设计牵扯的问题已经被划分到三个不同的层次,在每一个层次我们都要有特定的思考成果。在高层没有思考成熟的时候我们不往下一个层次进行,按照这样一个原则,细节被隔离在思维的围墙之外。
           下面一个问题就是,在设计中过程,三种视角对问题进行层次划分能起到什么作用?
     

  3. 三层视角--回头再说OO设计原则

            
    概念视角我们得到了领域的各种概念,对象要负责什么?这是一个高层策略,它通常是高度抽象的,是一个策略性的结论,关键一点:它是稳定的。只要概念不变请求者就和细节的变化隔离开了;细节问题的处理应该尽可能的往后推迟。关注对象要做什么,而不是怎么做,将这些细节实现隐藏起来帮助我们免于过早的介入细节。关注对象要做什么,就是在定义对象的责任,理解对象的最佳方式就是把它看作有责任的东西。

           规约视角,对象是一组可以被其它对象或对象自己调用的方法(也就是行为,怎么使用软件?);对象是有责任的我只需要关注对象的公共接口-这是我要求对象完成某些工作的交流渠道。只要对象的接口告诉我们它可以完成某项职责,不关注对象是怎样运行的。关注动机而非实现,是基本的OO设计原则,将实现隐藏在接口之后实际上是将对象的实现与它们的对象解耦了。

          实现视角,对象是代码和数据,以及它们之间的计算交互(软件怎么履行自己的责任?);走到这里我们才开始讨论实现细节。

          总结一下,Martin Fowler的三个视角来看对象:

    在概念层次上,对象是一组责任

    规约层次上,对象是一组可以被其他对象或者对象自己调用的方法

    在实现层次上对象是代码和数据,以及它们的计算交互

     

    到这里我们需要对OO基本原则做一个再思考了:

            从概念层到规约层我们的思考成果都是抽象的,他们是一个个抽象的概念,是一个个的行为;我们在概念层是对象的责任清晰化,在规约层我们看拥有不同责任的对象之间是怎样协作的。协作方式就是一种对象与对象之间的契约。对象的责任怎么划分?对象应该对自己负责,对象的责任应该尽量单一,这就是SRP原则。规约层我们定义的是对象间的交互契约,也就是接口,关注接口而非实现,我们做到了。

           概念层是最稳定的,规约层次之,实现是最不稳定的。所以高层模块不应该依赖低层模块,两者都应该依赖于抽象。细节应该依赖于抽象,这就是DIP原则。这个原则隐含的意思是:对象之间只在概念层次存在耦合,在实现层次不能耦合!

           我们定义的所有交互都是使用基类,那如果实现的时候某一个子类不能完全代替基类呢?那是不是所有的交互契约都出现问题了?一个从基类派生的子类应该支持基类的所有行为,子类必能替换基类,这就是LSP原则。

            可以看出对象的责任和交互被尽早的定义出来,这个过程中我们没有考虑具体对象在什么时期创建,映射到我们的设计过程中,创建型设计模式的应用往往是在设计的后期。

     

           结论:

  4. OO设计原则总结》一文中我提出了一个问题:如何更好的使用这些原则?怎样在实践中遵守这些原则,使用三种视角思考问题就是答案之一;
  5. 做设计时,注意力首先要放在高层关系上;
  6.  在面对对象设计开发过程中以概念 规约 实现三个视角类思考问题能提高我们的设计能力,避免过早陷入细节泥沼。

     

    附: Martin Fowler著作 UML Distilled》提到三种视角(perspective)的段落:
     

    Following the lead of Steve Cook and John Daniels (1994), I say that there are three perspectives you can use in drawing class diagrams- or indeed any model, but this breakdown is most noticeable in connection with class diagrams.

    • Conceptual. 
      If you take the conceptual perspective, you draw a diagram that represents the concepts in the domain under study. These concepts will naturally relate to the classes that implement them, but there is often no direct mapping. Indeed, a conceptual model should be drawn with little or no regard for the software that might implement it, so it can be considered language-independent. (Cook and Daniels call this the essential perspective.)
    • Specification. 
      Now we are looking at software, but we are looking at the interfaces of the software, not the implementation. Object-oriented development puts a great emphasis on the difference between interface and implementation, but this is often overlooked in practice because the notion of class in an OO language combines both interface and implementation. This is a shame, because the key to effective OO programming is to program to a class's interface rather than to its implementation. There is a good discussion of this in the first chapter of Gamma, Helm, Johnson, and Vlissides (1995). You often hear the word "type" used to talk about an interface of a class; a type can have many classes that implement it, and a class can implement many types.
    • Implementation. 
      In this view, we really do have classes and we are laying the implementation bare. This is probably the perspective used most often, but in many ways the specification perspective is often a better one to take.

    Understanding perspective is crucial to both drawing and reading class diagrams. Unfortunately, the lines between the perspectives are not sharp, and most modelers do not take care to get their perspective sorted out when they are drawing. Although I've found that this often does not matter too much between the conceptual perspective and the specification perspective, it is very important to separate the specification perspective and the implementation perspective.

    As I talk about class diagrams further, I will stress how each element of the technique depends heavily on the perspective.

    Perspective is not part of the formal UML, but I have found it extremely valuable when modeling and when reviewing models. The UML can be used with all three perspectives. By tagging classes with a stereotype (see page 79), you can provide an indication of the perspective. You mark classes with <<implementation class>> to show the implementation perspective, and with <<type>> for the specification and conceptual perspectives.

     

    UML Distilled Second Edition A Brief Guide to the Standard Object Modeling Language

    Martin Fowler   Kendall Scott

    Publisher: Addison Wesley

                    Second Edition August 18, 1999

                    ISBN: 0-201-65783-X, 224 pages