Java如何设计一个类

Java如何设计一个类

解决

针对继承带来的问题,可以采用复合的方式进行解决,即不用扩展现有的类,而是在新的类中增加一个私有域,它引用现有类的一个实例。因此现有类变成了一个新类的一个组件,新类中的每个实例方法就可以调用被包含的类的实例方法,并返回相应的结果,这称之为转发。

采用复合/转发的方式重写上面的TestHash,包含了两个部分:新类本身以及被包含的转发类:

// Wrapper class - uses composition in place of inheritance

public class InstrumentedSet extends ForwardingSet {

private int addCount = 0;

public InstrumentedSet(Set s) {

super(s);

}

@Override

public boolean add(E e) {

addCount++;

return super.add(e);

}

@Override

public boolean addAll(Collection c) {

addCount += c.size();

return super.addAll(c);

}

public int getAddCount() {

return addCount;

}

}

// Reusable forwarding class

public class ForwardingSet implements Set {

private final Set s;

public ForwardingSet(Set s) { this.s = s; }

public void clear() { s.clear(); }

public boolean contains(Object o) { return s.contains(o); }

public boolean isEmpty() { return s.isEmpty(); }

public int size() { return s.size(); }

public Iterator iterator() { return s.iterator(); }

public boolean add(E e) { return s.add(e); }

public boolean remove(Object o) { return s.remove(o); }

public boolean containsAll(Collection c) { return s.containsAll(c); }

public boolean addAll(Collection c) { return s.addAll(c); }

public boolean removeAll(Collection c) { return s.removeAll(c); }

public boolean retainAll(Collection c) { return s.retainAll(c); }

public Object[] toArray() { return s.toArray(); }

public T[] toArray(T[] a) { return s.toArray(a); }

@Override

public boolean equals(Object o) { return s.equals(o); }

@Override

public int hashCode() { return s.hashCode(); }

@Override

public String toString() { return s.toString(); }

} 在上面这个例子里构造了两个类,一个是用来扩展操作的包裹类,一个是用来与现有类进行交互的转发类,可以看到,在现在这个实现中包裹类不再直接扩展Set,而是扩展了他的转发类,而在转发类内部,现有Set类是作为它的一个数据域存在的,转发类实现了Set接口,这样它就包括了现有类的基本操作。每个转发动作都直接调用现有类的相应方法并返回相应结果。这样就将信赖于Set的实现细节排除在包裹类之外。有的时候,复合和转发的结合被错误的称为"委托(delegation)"。从技术的角度来说,这不是委托,除非包装对象把自身传递给被包装的对象。

什么时候使用继承?

只有当子类真正是超类的子类型(subtype)时,才适合用继承。对于两个类A和B,只有当两者之间确实存在"is-a"的关系的时候,类B才应该扩展A。如果打算让类B扩展类A,就应该确定一个问题:B确实也是A吗?如果不能确定答案是肯定的,那么B就不应该扩展A。如果答案是否定的,通常情况下B应该包含A的一个私有实例,并且暴露一个较小的、较简单的API:A本质上不是B的一部分,只是它的实现细节而已(使用API的客户端无需知道)。

相关推荐

古人说“人死为鬼,鬼死为聻”,聻是什么东西?那神仙死后又会变成什么呢?归墟?
古人说“人死为鬼,鬼死为聻”,聻是什么东西?那神仙死后又会变成什么呢?归墟?
古人说“人死为鬼,鬼死为聻”,聻是什么东西?那神仙死后又会变成什么呢?归墟?