委譲されるクラスは委譲したクラスが隠蔽する

f:id:mat5ukawa:20150923132954p:plain (一番進捗が出ているタスク, 一番進捗が出ていないタスク void → int)

設計

  • 顧客 | マネージャー、エンジニア1、 エンジニア2
    • が居るとする
  • 顧客は知りたい
    • エンジニア1、エンジニア2 が進めるタスクの内
    • 一番進捗が出ているタスク
    • 一番進捗が出ていないタスク

この時、どうシステム設計するのが良いか

A plan

「顧客がマネージャーに

『一番進捗が出ているタスク、一番進捗が出ているタスク』

を尋ねて、結果を教えてもらう」

B plan

「顧客が エンジニア1, エンジニア2 に進捗率を尋ね

『一番進捗が出ているタスク、一番進捗が出ているタスク』を弾き出す」

A plan の方が良い

少なくとも顧客の立場からしたら B plan は面倒だし不自然


実装

マネージャー, エンジニア1, エンジニア2 間で委譲を使う

f:id:mat5ukawa:20150923133629p:plain

src
  |
  +-- jp.ymatsukawa
      +-- Main.java
      |
      +-- delegation
           |
           + -- Manager.java
           + -- Engineer.java

jp.ymatsukawa/Main.java

package jp.ymatsukawa;

import jp.ymatsukawa.delegation.Manager;

public class Main {
  public static void main(String[] args) {
    Manager BPManager = new Manager();
    System.out.println(BPManager.getLeastProgressedTaskPercentage());
    System.out.println(BPManager.getMostProgressedTaskPercentage());
  }
}

System out

30
80

jp.ymatsukawa/delegation/Manager.java

package jp.ymatsukawa.delegation;

public class Manager {
  private Engineer inexperiencedEngineer = new Engineer(30);
  private Engineer veteranEngineer       = new Engineer(80);

  public int getMostProgressedTaskPercentage() {
    return Math.max(this.inexperiencedEngineer.getProgress(), this.veteranEngineer.getProgress());
  }

  public int getLeastProgressedTaskPercentage() {
    return Math.min(this.inexperiencedEngineer.getProgress(), this.veteranEngineer.getProgress());
  }
}

jp.ymatsukawa/delegation/Engineer.java

package jp.ymatsukawa.delegation;

class Engineer {
  private int taskProgress;
  protected Engineer(int taskProgress) {
    this.taskProgress = taskProgress;
  }

  public int getProgress() {
    return this.taskProgress;
  }
}

委譲されるクラスを隠蔽する目的

クライアントと委譲されるクラスの密結合を回避するため

  • 委譲フィールドを公開すると
    • B plan が発生し得る
    • App class と Engineer class が互いに密結合になる
    • Manager class が Engineer class の作業範囲を公開するだけの class になりうる

委譲フィールド公開版(極例)

f:id:mat5ukawa:20150923133107p:plain

src
  |
  +-- jp.ymatsukawa
      +-- Main.java
      |
      +-- delegation
           |
           + -- Manager.java
           + -- Engineer.java

jp.ymatsukawa/Main.java

package jp.ymatsukawa;

import jp.ymatsukawa.delegation.Manager;

public class Main {
  public static void main(String[] args) {
    Manager BPManager = new Manager();
    int engineer1Progress = BPManager.getInexperiencedEngineer().getProgress();
    int engineer2Progress = BPManager.getVeteranEngineer().getProgress();
    System.out.println(Math.min(engineer1Progress, engineer2Progress));
    System.out.println(Math.max(engineer1Progress, engineer2Progress));
  }
}

System out

30
80

jp.ymatsukawa/delegation/Manager.java

package jp.ymatsukawa.delegation;

public class Manager {
  private Engineer inexperiencedEngineer = new Engineer(30);
  private Engineer veteranEngineer       = new Engineer(80);

  public Engineer getInexperiencedEngineer() {
    return this.inexperiencedEngineer;
  }

  public Engineer getVeteranEngineer() {
    return this.veteranEngineer;
  }
}

jp.ymatsukawa/delegation/Engineer.java

package jp.ymatsukawa.delegation;

class Engineer {
  private int taskProgress;
  protected Engineer(int taskProgress) {
    this.taskProgress = taskProgress;
  }

  public int getProgress() {
    return this.taskProgress;
  }
}

蛇足

私の Java 委譲に対する現状認識

「作業を別クラスに任せること。公開度は自クラスまで(委譲フィールドは含めない)」