复用与继承/静态工厂与构造器

来源:互联网 发布:消防接线网络 编辑:程序博客网 时间:2024/05/16 05:57

# 1.复用与继承

  面向对象特性之一就是继承,通过继承可以实现代码复用与功能扩展。但是却破坏了另一种特性封装性,这样就很危险了,你底层实现本应封装好,可却被看得一清二楚,随意更改。而复用就很好的解决这个问题,不但如此,继承有的复用都有。通过在类中引用其他类,这样既保障了类的封装性,也保障了类功能扩展。

 如:假设有一个程序使用HashSet,为了查看它自创建以来曾经添加过多少个元素,我们可以通过继承扩展HashSet,重写add和addAll方法。
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;
  }
}
这段代码看上去没什么问题,假如执行下面的程序,我们期望getAddCount返回3,但它实际上返回的是6。
InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
System.out.println(s.getAddCount());
哪里出错了?
在HashSet内部,addAll方法是基于add方法来实现的,即使HashSet的文档中并没有说明这一细节,这也是合理的。因此InstrumentedHashSet中的addAll方法首先把addCount增加了3,然后利用super.addAll()调用HashSet的addAll实现,在该实现中又调用了被InstrumentedHashSet覆盖了的add方法,每个元素调用一次,这三次又分别给addCount增加了1,所以总共增加了6。
因此,使用继承扩展一个类很危险,父类的具体实现很容易影响子类的正确性。而复合优先于继承告诉我们,不用扩展现有的类,而是在新类中增加一个私有域,让它引用现有类的一个实例。这种设计称为复合(Composition)。

# 2.静态工厂与构造器

  静态工厂:不同于设计模式中的工厂,这样只是一个生成对象的方法,就是在类中实现一个私有的方法,返回类对象,像单例模式中,单例模式的实现就是通过静态工厂来实现,保障了对象的唯一性。

  构造器:每一个类都有一个默认的构造器,如果你需要自定义一个构造器,那就需要进行在构造器参数个数,类型等进行加以区分,构造器名字都是类名。

  静态工厂由于构造方法,不只是因为它能保证对象创造的唯一性,与重复使用,也因为它能自定义名字,很好的加以区分,并可以返回实现原返回类型的任何子类型,并在定义申明参数化类对象时很方便。

原创粉丝点击