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

原创 2012年03月21日 13:08:28

 

4.6 尽量让类中定义的每个方法尽可能多地使用包含的对象(即数据成员)
    这其实就是高内聚的翻版强调。如果每个类的情况并非如此,那很可能是这一个类表示了两个或更多的概念,记住一个类只应该表示一个概念。
    最明显的情况就是类的一半方法使用了一半的数据成员,而另一半方法使用了另一半的数据成员,那么这个类就应该一分为二。
    我们假设一个澡堂,有VIP客户和普通客户,各自有不同的服务(普通客户享受中专生服务,VIP客户享受大学生服务),则定义如下:

    class 澡堂
    {
         stack<中专生> 普通服务员;
         stack<大学生> VIP服务员;
         
         普通接待()
         {
              普通服务员.Pop().侍候();               
         }
         普通结帐()
         {
              普通服务员.Pop().结帐();
         }

         Vip接待()
         {
              VIP服务员.Pop().侍候();
         }
         VIP结帐()
         {
              VIP服务员.Pop().结帐();
         }
    }


 

    这是一个我经常看到的类似结构,这种结构不可避免地会在使用者的代码里进行很多条件判断,来确定到底调用那个版本的方法,而这种判断最好避免。
    原因在于这一个类包含了两个概念,一个是针对普通客户,一个是针对VIP客户,违反了本条原则,我们应当将其分开,这里可以考虑再次抽象

    class 澡堂
    {        
        abstract 接待();
        abstract 结帐();
    }
    class 普通澡堂:澡堂
    {
         stack<中专生> 服务员;         
         接待()
         {
              服务员.Pop().侍候();               
         }
         结帐()
         {
              服务员.Pop().结帐();
         }
    }
    class VIP澡堂:澡堂
    {
         stack<大学生> 服务员;

         Vip接待()
         {
              服务员.Pop().侍候();
         }
         VIP结帐()
         {
              服务员.Pop().结帐();
         }
    }


   

    这样这个类的使用者可以使用如下方法:

    澡堂 tmp=null;
    if(顾客 is 普通客户)
         tmp=new 普通澡堂();       
    if(顾客 is VIP客户)
         tmp=new VIP澡堂();
    tmp.接待();
    //......
    tmp.结帐();


 

    眼神好的可能马上就会提出,这里也进行了判断,但是这里的判断我们可以通过两种手段来处理
    一,字典
        在外部保存一个字典:Dictionary<顾客类型,澡堂> dic;
        那么上面的代码就成为下面这样:

        澡堂 tmp=dic[顾客类型];
        tmp.接待();
        //......
        tmp.结帐();


 

    二,简单工厂
        实现一个简单工厂,澡堂Factory,则使用代码如下:

        澡堂 tmp=澡堂Factory.Create(顾客类型);
        tmp.接待();
        //......
        tmp.结帐();


 

     这两种方式都可以在程序配置的时候进行调整,将类型的依赖延迟到配置细节中(而这正是类型注入的要旨,别被那些专有的很玄的框架名次忽悠,其实就是这么简单)。
    
   

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
  • 492
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:OOD沉思录 之 类和对象的关系--包含关系2
举报原因:
原因补充:

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