【Practical API Design学习笔记】代理和组合

    看下面算术类:

public class Arithmetica {
  public int sumTwo(int one, int second) {
    return one + second;
  }
  public int sumAll(int... numbers) {
    if (numbers.length == 0) {
      return 0;
    }
    int sum = numbers[0];
    for (int i = 1; i < numbers.length; i++) {
      sum = sumTwo(sum, numbers[i]);
    }
    return sum;
  }
  public int sumRange(int from, int to) {
    int len = to - from;
    if (len < 0) {
      len = -len;
      from = to;
    }
    int[] array = new int[len + 1];
    for (int i = 0; i <= len; i++) {
      array[i] = from + i;
    }
    return sumAll(array);
  }
}
当这个类发布出去后,使用这个类的人发现继承这个类,可以很容易地进行阶乘计算,于是定义类如下:
public final class Factorial extends Arithmetica {
  public static int factorial(int n) {
    return new Factorial().sumRange(1, n);
  }
  @Override
  public int sumTwo(int one, int second) {
    return one * second;
  }
}
后来,再下一个版本中,API开发者升级了这个API的某个方法,性能得以提升,如下:
public int sumRange(int from, int to) {
  return (from + to) * (Math.abs(to - from) + 1) / 2;
}

但是我们会看到,升级后的API对于使用该API的开发者写的子类Factorial就不适用了。

为了解决以上的问题,可以使用组合来代替继承。

先来看下表,下表中是java不同访问级别的声明方式的不同语义,有的只有一种语义,有的有多种。

表格中中间一列指的是主要的语义,右边一列指的是额外的含义。我们要用只要主要含义,没有额外含义的访问级别。

看下表,左列是有不同含义的访问级别,右列是改写的只有一种含义的。

如上,现在我们知道对于类中的方法如果存在多种语义,我们如何来重写这个类。

下面要做进一步转换,来使类中的方法有更清晰的语义。

看下面的代码:

public abstract class MixedClass {
  private int counter;
  private int sum;
  protected MixedClass() {
    super();
  }
  public final int apiForClients() {
    int subclass = toBeImplementedBySubclass();
    sum += subclass;
    return sum / counter;
  }
  protected abstract int toBeImplementedBySubclass();
  protected final void toBeCalledBySubclass() {
    counter++;
  }
}

如果一个类是由单一语义的方法组成,那么我们可以用两个类和一个接口来代替原来的抽象类。如下:

public final class NonMixed {
  private int counter;
  private int sum;
  private final Provider impl;
  private NonMixed(Provider impl) {
    this.impl = impl;
  }
  public static NonMixed create(Provider impl) {
    NonMixed api = new NonMixed(impl);
    Callback callback = new Callback(api);
    impl.initialize(callback);
    return api;
  }
  public final int apiForClients() {
    int subclass = impl.toBeImplementedBySubclass();
    sum += subclass;
    return sum / counter;
  }
  public interface Provider {
    public void initialize(Callback c);
    public int toBeImplementedBySubclass();
  }
  public static final class Callback {
    NonMixed api;
    Callback(NonMixed api) {
      this.api = api;
    }
    public final void toBeCalledBySubclass() {
      api.counter++;
    }
  }
}
这样,使用该API的人就可以如下使用:
@Test 
public void useWithoutMixedMeanings() {
  class AddFiveMixedCounter implements NonMixed.Provider {
    private Callback callback;
    public int toBeImplementedBySubclass() {
      callback.toBeCalledBySubclass();
      return 5;
    }
    public void initialize(Callback c) {
      callback = c;
    }
  }
  NonMixed add5 = NonMixed.create(new AddFiveMixedCounter());
  assertEquals("5/1 = 5", 5, add5.apiForClients());
  assertEquals("10/2 = 5", 5, add5.apiForClients());
  assertEquals("15/3 = 5", 5, add5.apiForClients());
}
综上所述,我们要用组合来代替继承。

转载于:https://my.oschina.net/tingzi/blog/133163

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值