OOD沉思录 之 类和对象的关系--包含关系4

原创 2012年03月23日 23:28:31

 

4.9 在实现语义约束时,最好根据类定义来实现。但是这经常会导致泛滥成灾的类,在这种情况下约束应当在类的行为中实现,通常在类的构造函数中实现,但不是必须如此。
    还是以汽车为例,我们看汽车的定义,为了集中注意力,先只关心汽车的发动机

 

    class 汽车
    {
        汽车(发动机 para)
        {
            m_发动机=para;
        }
        发动机 m_发动机;
    }
    class 发动机{...}



    我们可以定义奥迪A6,凯梅瑞等等汽车

 

    class 奥迪A6:汽车{......}
    class 凯梅瑞:汽车{......}



    同样我们可以定义丰田发动机,三菱发动机等等

 

    class 丰田发动机:发动机{......}
    class 三菱发动机:发动机{......}


 

 

    问题,假设奥迪A6只能使用丰田发动机,凯梅瑞只能使用三菱发动机,问题是汽车只包含了抽象的发动机,对抽象的汽车类来说,所有发动机没有任何区别,那么需要我们把这个
约束条件放到合适的位置。
    首先我们考虑在构造函数中加以约束,那么奥迪A6,凯梅瑞汽车的构造函数就分别如下:

 

    奥迪A6(丰田发动机 para):base(para){}
    凯梅瑞(三菱发动机 para):base(para){}




    这种方式很可靠,能保证系统里不会出现状态非法的汽车(奥迪A6使用了三菱发动机,就是非法状态)
    这种方式的问题在于,如果汽车和发动机的种类繁多,会导致出现泛滥成灾的类。
    第二种方式,我们不保证汽车的状态合法,而是在汽车的行为里检查,状态是不是合法。
    我们看看汽车的启动方法,可以如下定义

 

    class 汽车
    {
         。。。。。。
         void 启动()
         {
              //先检查汽车的状态,如果状态不合法,则告诉用户汽车无法启动,因为什么原因;如果合法,则开启发动机
              if(检查状态())
                m_发动机.启动();
              else
                throw "汽车使用了不配套的发动机!";              
         }
    }


 


    检查状态()这个该怎么实现呢?答案是必须有一个地方存储了汽车可以使用的发动机列表(当然也可以是发动机能匹配的汽车),我们可以实现一个字典,来保存
这个信息,然后根据这个字典来检查汽车状态。
    这个字典的样子和下面差不多
    Key                     Value
    奥迪A6                  丰田发动机
    凯梅瑞                  三菱发动机
    。。。。。。            。。。。。。
   

4.10 在类的构造函数中实现语义约束时,把约束测试放到构造函数领域所允许的尽量深的包含层次中。
    在构造函数中实现约束时,应该遵循这条原则,当然我还没想到如果没有遵循这条原则,构造函数会是什么样子?
    在汽车类里怎么实现这个约束?汽车类并不知道有奥迪A6或者凯梅瑞,这是继承的一个原则(派生类知道基类,但是基类不应该知道派生类),我能想到的实现方式就是如下

 

    class 汽车
    {
         汽车(发动机 para)
         {
               if(!检查状态(para))//这个检查状态的实现和上面类似,从一个字典里查询
                   throw new "发动机不匹配";              
         }
    }



    这种方式确实不会产生非法状态的汽车,但是对使用者来说很不友好。

4.11 约束所依赖的语义信息如果经常改变,那么最好放在一个集中式的第三方对象中。
    4.9里的字典内容如果经常变化,那么最好存放到外部文件里,否则可以作为汽车类的静态属性来实现。

4.12 约束所依赖的语义信息如果很少改变,那么最好分布在约束所涉及的各个类中。

     类包含的数据成员分为两种,一种是描述性的,如长宽高颜色等,另一种是具有行为的子对象,如汽车包含方向盘,而方向盘本身就是一个具有"有意义的行为"的对象。
     前者我们不去仔细讨论,只讨论后者。

4.9 类必须知道它包含什么,但是不能知道谁包含它。
    如汽车必须知道包含了方向盘(否则汽车的左转,右转行为都无法实现),但是方向盘不能知道包含它的汽车,否则方向盘就无法重用到其它的汽车上。

4.10 同一个类包含的对象之间不应当有使用关系。
    从复用性和复杂性角度考虑。

 


OOD沉思录 之 类和对象的关系--包含关系3

4.7 类包含的对象数目不应当超过开发者短期记忆数量,这个数目通常应该是6左右   4.8 让系统在窄而深的包含体系中垂直分布     假设有如下两份菜单:     正餐--->甜瓜    ...

OOD沉思录 之 面向动作与面向对象1--避免全能类

面向过程的软件开发通过非常集中化的控制机制来分解功能,在程序设计中表现就是大量的条件判断,深层次的循环嵌套等。这种模式下,我们可以通过分析方法的参数,局部变量及其访问的全局变量来得到方法对数据的依赖性...

如何构建类--《一个面向对象程序范例--沉思录》读后

最近在学 C++
  • locklzg
  • locklzg
  • 2014年06月10日 17:12
  • 606

C++沉思录读书笔记(29章)- 应用器,操纵器和函数对象

我们经常在程序中看见诸如int n; cout 对于cout ostream& operator

c++沉思录笔记(21章代码)浅谈函数对象

标准库中有一个函数  find_if (#include )接受一对输入迭代器和一个谓词函数作为参数。 例如有一谓词函数如下: bool greater100(int n) { return...

C++沉思录 第八章 面向对象程序范例

c++沉思录第八章的示例程序很有意思。程序虽小,却很好地诠释了面向对象编程的思想。 正如书上说的仔细研究还是有所收获的。先上代码codeExpr_node.h#pragma once #includ...

函数对象-摘自《C++沉思录》Andrew Koenig

函数对象提供了一种方法,将要调用的
  • locklzg
  • locklzg
  • 2014年07月21日 10:51
  • 486

C++沉思录第八章算数表达式树的面向对象问题的分析

刚开始看沉思录,觉得太枯燥。到了第八章,作者关于面向对象问题的分析,我follow书上的设计开发,理解了一些以前只是在书上看到的概念。 给自己做几点注解吧: 1.虚基类用来表达所有的继承类的共有特点,...

C++沉思录读书笔记(8章)-一个面向对象程序范例1

这个例子很好的展示了面向对象编程的三个要素:数据抽象、继承和动态绑定。 问题:算术表达式的表达式树, 如(-5)*(3+4)对应的表达式树为: 我们希望通过调用合适的函数来创建这样的树...

一个面向对象程序范例-摘自《C++沉思录》Andrew Koenig

通常认为,面向对象编程有3个要素:数据抽象、继承以及
  • locklzg
  • locklzg
  • 2014年06月10日 15:34
  • 493
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:OOD沉思录 之 类和对象的关系--包含关系4
举报原因:
原因补充:

(最多只允许输入30个字)