リファクタリングの実例1:第1回

Advertisement

元となるソースコード

※ここで登場するコードは某所で実際に稼動しているコードをアレンジして(雰囲気的には、ほとんどそのまま)乗せています。このシステムは短いスパンでの修正・リリースという形式で開発を行っているプロジェクトで作成され、今後も多くの変更が加えられると予想されるため、変更に強いコードでなければなりません。

Product クラス
public class Product{

    public Product(String name, String teika){
        this.name = name;
        this.teika = teika;
    }

    /** 製品名 */
    public String name;

    /** 製品の定価 */
    public String teika;

    /** 製品自体にエラーが存在するか */
    public boolean error;
}

Main クラス(クライアント)
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 製品を利用するクラス
 */
public class Main{
    public static void main(String[] args){
        // 製品の作成
        Product product = new Product("name", "1000");

        // エラー設定
        Pattern pattern = Pattern.compile("[A-Za-z0-9]+");
        Matcher matcher = pattern.matcher(product.name);
        product.error = !matcher.matches();

        pattern = Pattern.compile("[0-9]+");
        matcher = pattern.matcher(product.teika);
        product.error = product.error | !matcher.matches();

        // エラー判定
        if(product.error){
            System.out.println("この製品は内部にエラーを含んでいます。");
        }else{
            System.out.println("この製品にエラーはありません。");
        }
    }
}
このプログラムでは Product クラスは製品を表し、内部に名前と価格を保持している。クライアントは製品を作成し、エラーが含まれていないかチェックを行った後、製品を利用する。

問題点を考える

上記のプログラム設計の欠点を探してみる。

まず、Product クラスのメンバ変数(name, teika)が public となっているため、クライアント側で Product の内部構造に依存するコードが書かれている。詳しい話はカプセル化を参照。
よって、次の問題が見つかる。
  • Productクラスの変数の型を変更した場合、Product・クライアント両方のコードを修正しなければならない。
次にエラーチェックに注目してみる
Product クラスは複数のクライアントから利用されることが考えられる。この場合、次の問題点が考えられる。
  • クライアントからProductクラスを使用する際、毎回エラーチェック処理を記述しなければならない。
  • 複数のクライアントで、クライアントごとに異なるエラー判定ロジックを採用したい場合に適しているように見えるが、ロジックが変更になると、同じエラーチェックを行っているすべてのクライアントコードを修正しなければならない。

さらに次の要求を、常に満たしていなければならない。
  • プログラムの振る舞いを変更してはいけない。
  • エラーチェック処理のロジックは複数パターンあり、クライアントによって異なる。
以上の問題を踏まえ、リファクタリングを行うことにする。

Advertisement

ショートカット

634トップページ
このカテゴリのトップページに戻る
634ラボ

サイト検索

Google

Web サイト内

Y!ログール