继承这里指的是,extends一个父类
复合其实感觉像是一个包装类
和设计模式中的Decorator模式一样吗?
从这个例子里面看出
继承的方式:InstrumentedHashSet extends HashSet implements Set
扩展的子类方法依赖父类的实现细节,造成这个子类很脆弱。
改进后的InstrumentedHashSet implements Set,并且包含一个私有final Set变量,在这个类中调用被包含实例中已有的方法,返回它的结果,这个过程称为转发(forwarding)。
网上摘抄:
这样做等同于新建一个类,而这个类的全部作用就是给原来继承的父类的所有已知方法进行代理。
代理方法是死的,不会随原父类方法的扩充而改变,他只是调用原父类的方法,所以,当原父类新增方法时这个代理的类是不知道也不会受到影响的。
这样做也是有缺陷的:
虽然这样不会因为父类的扩展和子类发生冲突,但同样的父类扩展的好处也不会被子类自动继承,这时需要手动去更新代理类,设想一下,在一个比较复杂的系统中,所有继承关系都使用这种复合关系,那么任何非叶级的类增加方法都要在该类的复合类中增加代理方法,代码维护工作量会增加,而且父类增加方法时无法立即知道新方法与子类可能存在的冲突,而导致了重复的工作。
复合其实感觉像是一个包装类
和设计模式中的Decorator模式一样吗?
package CompositionBetterInheritance;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
public class InstrumentedHashSet<E> extends HashSet<E>{
private int addCount = 0;
public InstrumentedHashSet(){}
public InstrumentedHashSet(int initCap, float loadFactor){
super(initCap, loadFactor);
}
@Override
public boolean add(E e){
addCount++;
return super.add(e);
}
@Override
public boolean addAll(Collection<? extends E> c){
addCount += c.size();
return super.addAll(c);
}
public int getAddCount(){
return addCount;
}
public static void main(String[] args) {
InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("1","2","3"));
System.out.println(s.getAddCount());//输出6,因为allAll方法中调用了add方法
}
}
package CompositionBetterInheritance;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class InstrumentedHashSet2<E> implements Set<E>{
private int addCount = 0;
private final Set<E> s;
public InstrumentedHashSet2(Set<E> s) {
this.s = s;
}
public boolean add(E e){
addCount++;
return s.add(e);
}
public boolean addAll(Collection<? extends E> c){
addCount += c.size();
return s.addAll(c);
}
public int getAddCount(){
return addCount;
}
@Override
public void clear() {
s.clear();
}
@Override
public int size() {
return s.size();
}
@Override
public boolean isEmpty() {
return s.isEmpty();
}
@Override
public boolean contains(Object o) {
return s.contains(o);
}
@Override
public Iterator<E> iterator() {
return s.iterator();
}
@Override
public Object[] toArray() {
return s.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return (T[]) s.toArray(a);
}
@Override
public boolean remove(Object o) {
return s.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return s.containsAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return s.retainAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return s.removeAll(c);
}
public static void main(String[] args) {
InstrumentedHashSet2<String> s = new InstrumentedHashSet2<String>(new HashSet<String>());
s.addAll(Arrays.asList("1","2","3"));
System.out.println(s.getAddCount());//这里输出3,正确
}
}
从这个例子里面看出
继承的方式:InstrumentedHashSet extends HashSet implements Set
扩展的子类方法依赖父类的实现细节,造成这个子类很脆弱。
改进后的InstrumentedHashSet implements Set,并且包含一个私有final Set变量,在这个类中调用被包含实例中已有的方法,返回它的结果,这个过程称为转发(forwarding)。
网上摘抄:
这样做等同于新建一个类,而这个类的全部作用就是给原来继承的父类的所有已知方法进行代理。
代理方法是死的,不会随原父类方法的扩充而改变,他只是调用原父类的方法,所以,当原父类新增方法时这个代理的类是不知道也不会受到影响的。
这样做也是有缺陷的:
虽然这样不会因为父类的扩展和子类发生冲突,但同样的父类扩展的好处也不会被子类自动继承,这时需要手动去更新代理类,设想一下,在一个比较复杂的系统中,所有继承关系都使用这种复合关系,那么任何非叶级的类增加方法都要在该类的复合类中增加代理方法,代码维护工作量会增加,而且父类增加方法时无法立即知道新方法与子类可能存在的冲突,而导致了重复的工作。