类委托
设计大型的面向对象系统的一个常见问题就是由继承的实现导致的脆弱性。当你扩展一个类并重写某些方法时,你的代码就变得依赖你继承的那个类的实现细节。举个例子,当你打算实现一个计数的集合时,会优先考虑继承现有的集合。代码如下:
public class CountSet extends HashSet<String> {
private int count = 0;
@Override
public boolean add(String s) {
count += 1;
return super.add(s);
}
@Override
public boolean addAll(Collection<? extends String> c) {
count = count + c.size();
return super.addAll(c);
}
public int getCount() {
return count;
}
}
逻辑上没有什么问题。但是你调用addAll
的时候,数量就会出错。当你深究下去的时候,会发现addAll
里面还会调用add
方法。所以导致了我们的数量出了问题!嗯~~ 这就是刚才说的子类的实现依赖于父类
。这样就会出现了一个问题。当子类的实现会依赖与父类的情况下,我们的父类发生改变就会影响到子类。这样导致了父类和子类之前会有耦合。
Joshua Bloch
在Effective Java Third Edition
中提到一点,组合优于继承。虽然继承有强大的功能。但不是最好的工具。当我们在做设计的时候,应该多考虑一下,这个类是什么东西。这个类有什么东西。它是否能否被扩展。现在我们使用组合来重写上面的代码.
public class CountSet<E> implements Set<E> {
private Set<E> sets=new HashSet<E>();
@Override
public int size() {
return sets.size();
}
@Override
public boolean isEmpty() {
return sets.isEmpty();
}
@Override
public boolean contains(Object o) {
return sets.contains(o);
}
@Override
public Iterator<E> iterator() {
return sets.iterator();
}
...
}
虽然解决了上面的问题,但是你会发现。多了很多样本代码。而kotlin
中的委托就可以解决上述的代码。 而我们只需要关心自己想处理的逻辑即可。
class CountSet<T>(val set: MutableSet<T> = hashSetOf()) : MutableSet<T> by set {
var count = 0
override fun add(element: T): Boolean {
count += 1
return set.add(element)
}
override fun addAll(elements: Collection<T>): Boolean {
count += elements.size
return set.addAll(elements)
}
}
网友评论