• EffectiveC++-条款38:通过复合塑模出 has-a 或 根据某物实现出


    一. 内容

    1. 在程序员之间复合(composition)有很多同义词,包括 layering(分层),containment(内含),aggregation(聚合)和 embedding(内嵌)。

    2. 复合(composition)是类型之间的一种关系:当某种类型的对象内含其他类型的对象。举例,一个人可以有名字,有地址,有手机号码:

      class Address;
      class PhoneNumber;
      class Person {
      public:
          //...
      private:
          std::string name;  //复合对象
          Address& Address;
          PhoneNumber& VoiceNumber;
          PhoneNumber& FaxNumber;
      };
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      条款32曾说,public 继承是一种 is-a 的意义,复合也有它们的意义。复合意味着 has-a(有一个)或 is-implemented-in-terms-of (根据某物实现出)。上述的 Person class 就演示出 has-a 关系:Person 有一个名称,有一个地址,以及语音和传真电话号码。但你不会说,Person 是一个名称,人是一个地址。对于大多数人,这应该不难理解。

    3. 比较麻烦的是区分:is-a(有一个) 和 is-implemented-in-terms-of (根据某物实现出)这两种对象关系。这两种关系其实是在不同领域的表现,如果对象只是你所塑造的世界中的某个物品,某些人物等,那这样的对象就属于应用域部分,如果对象需要负责你所塑造世界的细节部分,是规则的制定者和执行者,那这样的对象就属于实现域部分。当对象处于应用域,它就是 has-a 的关系,当对象处于实现域,它就是 is-implemented-in-terms-of 的关系。

    4. 假如你需要一个 template,希望制作一个sets,用于表示不重复对象,由于复用是一件美妙的事,直觉是采用标准程序库提供的 set template。是的,如果他人所写的 template 合乎需求,我们何必再写另外一个?

      不幸的是,原生的 set 实现:每个元素耗用三个指针的额外开销。虽然以平衡查找树(balance search tree)实现使得它们在查找,安插,移除元素时保证拥有对数时间的效率,当速度比空间重要,这是个通情达理的设计,但当空间比速度重要时,似乎我们终究还得写个自己的 template。

      如果你是位数据结构专家,你就会知道,实现 sets 的方法太多了,其中一种便是在底层采用 linked lists,恰好标准程序库有一个 list template,我们便可以复用它们。

      你应当了解的是:set 对象可以根据一个 list 对象实现出来。也就是说 set 成员函数可大量倚赖 list 及标准程序库其他部分提供的机能来完成

      template <typename T>
      class Set {
      public:
          bool Contains(const T& Item) const;
          void Insert(const T& Item);
          void Remove(const T& Item);
          size_t Size() const;
      private:
          std::list<T> Rep;
      };
      
      template <typename T>
      bool Set<T>::Contains(const T& Item) const {
          bool Result=std::find(Rep.begin(),Rep.end(),Item)!=Rep.end();
          return Result;
      }
      
      template <typename T>
      void Set<T>::Insert(const T& Item) {
          if(!Contains(Item)) {
              Rep.push_back(Item);
          }
      }
      
      template <typename T>
      void Set<T>::Remove(const T& Item) {
          typename std::list<T>::iterator It=std::find(Rep.begin(),Rep.end(),Item);
          if (It!=Rep.end()) {
              Rep.erase(Item);
          }
      }
      
      template <typename T>
      size_t Set<T>::Size() const {
          return Rep.size();
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36

      显然,set 和 list 的关系是 is-implemented-in-terms-of,而不单单是 has-a 的关系。

    二. 总结

    1. 复合(composition)的意义和 public 继承完全不同。
    2. 在应用域(application domain),复合意味 has-a (有一个)。在实现域(implementation domain),复合意味 is-implemented-in-terms-of(根据某物实现出)。
  • 相关阅读:
    Day01 嵌入式 -----流水灯
    [公派访问学者]申请条件及选拔方法
    HOperatorSet.Connection 有内存泄漏或缓存
    只有微信账号,我可以查询聊天记录吗?
    BP简单循环网络(以2020年华为杯研究生数学建模竞赛中的E题抛砖引玉)
    iOS App更换图标Logo(本地更换)
    SQL注入漏洞:CMS布尔盲注python脚本编写
    加载 proc 和 devpts 文件系统
    Slf4j打印异常的堆栈信息
    Python学习第九篇:zipfile 库操作压缩包
  • 原文地址:https://blog.csdn.net/m0_51819222/article/details/125885257