Effective C++——条款38(第6章)

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

Model "has-a" or "is-implemented-in-terms-of" through composition

    复合(composition)是类型之间的一种关系,当某种类型的对象内含它种类型的对象,便是这种关系
.例如:
class Address { ... };
class PhoneNumber { ... };
class Person {
public:
    ...
private:
    std::string name;
    Address address;
    PhoneNumber voiceNumber;
    PhoneNumber faxNumber;
};
    本例中的Person对象由string,Address,PhoneNumber构成.在程序员之间,复合(compostion)这个术语有许多同义词,包括layering(分层),containment(内含),aggregation(聚合)和embedding(内嵌).
    条款32曾说,"public继承"带有is-a的意义. 复合也有它自己的意义.实际上它有两个意义, 复合意味has-a(有一个)或is-implemented-in-terms-of(根据某物实现出).那是相当于在软件中处理两个不同的领域.程序中的对象相当于塑造的世界中的某些事物,例如人,汽车等等.这样的对象属于应用域(application domain)部分.其他对象则纯粹是实现细节上的人工制品,像是缓冲区,互斥器,查找树等等.这些对象相当于软件的实现域. 当复合发生于应用域内的对象之间,表现出has-a的关系;当它发生于实现域则是表现is-implementation-in-terms-of的关系.
    比较麻烦的是区分is-a和is-implementation-in-terms-of这两种对象关系.假设需要一个 template,希望制造出一组 class 用来表现由不重复对象组成的sets.由于复用(reuse)是件美妙的事情,直觉上是采用标准程序库提供的set template.
    不幸的是set的实现往往招致"每个元素耗用三个指针"的额外开销.因为sets通常以平衡查找树实现而成,使它们在查找,插入,删除元素时保证拥有对数时间效率.当速度比空间重要,这是个合理的设计,但如果程序是空间比速度重要的?那么标准程序库的set就是一个错误的选择,似乎还是需要写个自己的 template.
    但是实现set还可以在底层采用linked list,而标准程序库恰好有一个list template,于是可以复用它.让set template 继承std::list,也就是让set<T>继承list<T>.于是声明set
template 如下:
template <typename T>                
class Set : public std::list<T> { ... };    // 错误的做法
    正如 条款32所说,如果对D使用 public 继承B,那么B的每一件事对D也必须为真.实际上list中可以被插入两个相同的元素,对Set而言,这是错误的.
    由于这两个 class 之间并非is-a的关系,所以 public 继承不适合来模塑它们.正确的做法是,Set对象可根据一个list对象实现出来:
template <class T>
class Set {
public:
    bool member(const T& item) const;
    void insert(const T& item);
    void remove(const T& item);
    std::size_t size() const;
private:
    std::list<T> rep;
};
    Set成员函数可大量依赖list以及标准程序库其他部分提供的机能来完成:
template <typename T>
bool Set<T>::member(const T& item) const {
    return std::find(rep.begin(), rep.end(), item) != rep.end();
}
template <typename T>
void Set<T>::insert(const T& item) {
    if (!member(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(it);
}
template <typename T>
std::size_t Set<T>::size() const {
    return rep.size();
}
    这些函数如此简单,因此都适合成为inlining候选人.但请记住,在做任何与inlining有关的决定之前,应该先看看条款30.
    注意:
    复合(compostion)的意义和 public 继承完全不同.
    在应用域(application domain),复合意味has-a(有一个).在实现域(implementation domain),复合意味is-implementation-in-terms-of(根据某物实现出).

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值