欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 美景 > Java高效编程(18):优先使用组合而非继承

Java高效编程(18):优先使用组合而非继承

2024/10/24 19:20:02 来源:https://blog.csdn.net/nokiaguy/article/details/142705131  浏览:    关键词:Java高效编程(18):优先使用组合而非继承

继承是一种实现代码重用的强大方式,但并不总是解决问题的最佳工具。只有当子类和父类之间存在真正的“是一个”关系时,继承才是合适的。例如,猫是动物,所以Cat类可以继承Animal类。不当使用继承会导致脆弱的软件设计。在包内使用继承是安全的,因为子类和父类的实现都由相同的程序员控制。当扩展那些为继承而专门设计并有文档说明的类时(第19条),使用继承也是安全的。然而,在跨包边界继承普通的具体类则很危险。请记住,本书中所说的“继承”是指实现继承(即一个类扩展另一个类)。接口继承(即类实现接口或一个接口扩展另一个接口)通常没有这些问题,因为接口继承只涉及方法的签名,而不涉及具体的实现细节。

与方法调用不同,继承违反了封装原则[Snyder86]。换句话说,子类为了正确地工作,依赖于父类的实现细节。父类的实现可能会在不同版本中发生变化,如果发生变化,子类可能会失效,即使子类的代码未作任何修改。因此,除非父类的作者专门设计并记录了它可以被扩展,否则子类必须与父类同步演进。这种依赖父类实现细节的方式增加了维护难度,也使得代码更加脆弱。

为了解释这一点,我们假设有一个程序使用了HashSet。为了优化性能,我们需要查询HashSet在创建后添加了多少元素(不是当前大小,因为移除元素后大小会减小)。为此,我们编写了一个HashSet的变体,它记录尝试插入元素的次数,并提供一个访问器来获取此计数。HashSet类包含两个可以添加元素的方法:addaddAll,因此我们需要覆盖这两个方法:

// 错误的做法 - 不恰当的使用继承!
public class InstrumentedHashSet<E> extends HashSet<E> {// 尝试插入的元素数量private int addCount = 0;public InstrumentedHashSet() {}public InstrumentedHashSet(int initCap, float loadFactor) {super(initCap, loadFactor);}@Overridepublic boolean add(E e) {addCount++;return super.add(e);}@Overridepublic boolean addAll(Collection<? extends E> c) {addCount += c.size();return super.addAll(c);}public int getAddCount() {return addCount;}
}

这个类看起来似乎合理,但实际上并不起作用。假设我们创建一个实例并使用addAll方法添加三个元素。注意,我们使用了Java 9引入的静态工厂方法List.of创建列表;如果您使用的是更早的版本,可以使用Arrays.asList替代:

InstrumentedHashSet<String> s = new InstrumentedHashSet<>();
s

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com