委托

147 阅读1分钟

除了组合和继承以外还有第三种重用关系,称为委托。但Java并不直接支持委托。

委托介于组合和继承之间,因为如果将一个成员对象放在正在构建的类中(组合),但同时在新类中公开来自成员对象的所有方法(继承)。

例如,宇宙飞船需要一个控制模块:

public class SpaceShipControls {
  void up(int velocity) {}
  void down(int velocity) {}
  void left(int velocity) {}
  void right(int velocity) {}
  void forward(int velocity) {}
  void back(int velocity) {}
  void turboBoost() {}
}

建造宇宙飞船的一种方法是使用继承:

public class
DerivedSpaceShip extends SpaceShipControls {
  private String name;
  public DerivedSpaceShip(String name) {
    this.name = name;
  }
  @Override
  public String toString() { return name; }
  public static void main(String[] args) {
    DerivedSpaceShip protector =
        new DerivedSpaceShip("NSEA Protector");
    protector.forward(100);
  }
}

然而, DerivedSpaceShip 并不是一种真正的 SpaceShipControls ,即使你“告诉” DerivedSpaceShip 调用 forward()。

更准确地来说,一艘宇宙飞船包含了 SpaceShipControls,同时 SpaceShipControls 中的所有方法都暴露在宇宙飞船中。 并非一艘飞船有了控制器后就能起飞,而是飞船通过飞船控制器来起飞。委托解决了这个难题:

public class SpaceShipDelegation {
  private String name;
  private SpaceShipControls controls =
    new SpaceShipControls();
  public SpaceShipDelegation(String name) {
    this.name = name;
  }
  // Delegated methods:
  public void back(int velocity) {
    controls.back(velocity);
  }
  public void down(int velocity) {
    controls.down(velocity);
  }
  public void forward(int velocity) {
    controls.forward(velocity);
  }
  public void left(int velocity) {
    controls.left(velocity);
  }
  public void right(int velocity) {
    controls.right(velocity);
  }
  public void turboBoost() {
    controls.turboBoost();
  }
  public void up(int velocity) {
    controls.up(velocity);
  }
  public static void main(String[] args) {
    SpaceShipDelegation protector =
      new SpaceShipDelegation("NSEA Protector");
    protector.forward(100);
  }
}

方法被转发到底层 control 对象,因此接口与继承的接口是相同的。但是,你对委托有更多的控制,因为你可以选择只在成员对象中提供方法的子集。

虽然Java语言不直接支持委托,但是开发工具常常支持。

但是可以通过 JetBrains Idea IDE 自动生成。