共通関数継承のデメリットを説明せよ

共通関数継承とは、あるクラスで共通的に使うだろう関数やメンバを、親クラスのメソッドやメンバとして定義するパターンだ。Constant interfaceパターンimport staticあたりが関係するアンチパターンとされるモノの一つで、神様ルートクラスを嫌い、POJOを好むのあたりの、ごく初歩な議論になるだろうと思う。

package spike;

public abstract class SuperUtil {

  /**
   * 時刻形式の文字列から、日付部分を抜き出す
   */
  protected String timestamp2Date(String timestamp) {
    if (validTimestamp(timestamp)) return timestamp.substring(0, 10);
    return "";
  }

  /**
   * 時刻形式の文字列から、時間部分を抜き出す
   */
  protected String timestamp2Time(String timestamp) {
    if (validTimestamp(timestamp)) return timestamp.substring(11, 8);
    return "";
  }
  
  /**
   * 時刻形式の文字列かチェックする
   */
  protected boolean validTimestamp(String str) {
    // ...
    return true;
  }
}
package spike;

public interface CommonMsg {
  public static final String ERROR_MSG_01 = "時刻形式が正しくありません";
}
package spike;

public class SubClass extends SuperUtil implements CommonMsg {
  private String timestamp;

  public void setTimestamp(String timestamp) {
    if (validTimestamp(timestamp)) this.timestamp = timestamp;
    throw new RuntimeException(ERROR_MSG_01);
  }
	
  public String getDate() {
    return timestamp2Date(timestamp);
  }
	
  public String getTime() {
    return timestamp2Time(timestamp);
  }
}

これは、とりあえず下のようにすべきだろう。とりあえず、だよ。

package spike;

public class SuperUtil {

  /**
   * 時刻形式の文字列から、日付部分を抜き出す
   */
  public static String timestamp2Date(String timestamp) {
    if (validTimestamp(timestamp)) return timestamp.substring(0, 10);
    return "";
  }

  /**
   * 時刻形式の文字列から、時間部分を抜き出す
   */
  public static String timestamp2Time(String timestamp) {
    if (validTimestamp(timestamp)) return timestamp.substring(11, 8);
    return "";
  }
  
  /**
   * 時刻形式の文字列かチェックする
   */
  public static boolean validTimestamp(String str) {
    // ...
    return true;
  }
}
package spike;

public class CommonMsg {
  public static String ERROR_MSG_01 = "時刻形式が正しくありません";
}
package spike;

import static spike.CommonMsg.*;
import static spike.SuperUtil.*;

public class SubClass {
  private String timestamp;

  public void setTimestamp(String timestamp) {
    if (validTimestamp(timestamp)) this.timestamp = timestamp;
    throw new RuntimeException(ERROR_MSG_01);
  }
  
  public String getDate() {
    return timestamp2Date(timestamp);
  }

  public String getTime() {
    return timestamp2Time(timestamp);
 }
}

さて。これを隣の同僚にどう説明したらいいものか悩み、先のエントリのアンチパターンからは外してみた。

リスコフの置換原則が破られる、試験性が落ちる、必要性がないなど、いろいろな理由は付けられるわけだけど、他のアンチパターンに見られるようなインパクトが見いだせないんだよなぁ。「どっちでもいいことにこだわりやがって」という印象を残さないくらい、強烈に説得したいんだが…。

ということで分けてみたよ、という言い訳エントリでした。