Java
Android
リファクタリング

[読書メモ]リファクタリング - ポリモーフィズムによる条件記述の置き換え

(What)どんな状況?

https://qiita.com/takutotacos/items/654e204d618d2059de7f
↑こんな状況

ポリモーフィズムによる条件記述の置き換えに関するメリットも↑記事に書いてます。

(How)どう解消する?

今回の記述を作成するためには、まず前提として必要な継承構造が存在している必要があります。

状況のおさらい

改修前のコード.java
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case REQUEST_CODE_FOR_EVALUATION_SEND:
                       // 何かの処理
            break;
        case REQUEST_CODE_FOR_SMS_SEND_ACTIVITY:
                       // 何かの処理
            break;
        case REQUEST_CODE_FOR_CAMERA_USAGE:
                       // 何かの処理
            break;
        default:
    }
}
改修準備(必要な継承構造の作成)ができた.java
class ActivityResult {
    public static final int REQUEST_CODE_FOR_EVALUATION_SEND = 1;
    public static final int REQUEST_CODE_FOR_SMS_SEND_ACTIVITY = 2;
    public static final int REQUEST_CODE_FOR_CAMERA_USAGE = 3;

    static ActivityResult create(int requestCode) {
        switch (requestCode) {
            case REQUEST_CODE_FOR_EVALUATION_SEND:
                return new ActivityResultEvaluationSend();
            case REQUEST_CODE_FOR_SMS_SEND_ACTIVITY:
                return new ActivityResultSmsSend();
            .. // 他のコードについても同様
        }
    }

    private ActivityResult() {}

    abstract int getRequestCode();
}

class ActivityResultEvaluationSend extends ActivityResult {
    @Override
    public int getRequestCode() {
        return ActivityResult.REQUEST_CODE_FOR_EVALUATION_SEND;
    }
}

class ActivityResultSmsSend extends ActivityResult {
    @Override
    public int getRequestCode() {
        return ActivityResult.REQUEST_CODE_FOR_SMS_SEND_ACTIVITY;
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    ActivityResult result = ActivityResult.create(requestCode);
    // @todo resultに処理を実装する。
}

改修する

改修準備(必要な継承構造の作成)ができた.java
public abstract class ActivityResult {
    public static final int REQUEST_CODE_FOR_EVALUATION_SEND = 1;
    public static final int REQUEST_CODE_FOR_SMS_SEND_ACTIVITY = 2;
    public static final int REQUEST_CODE_FOR_CAMERA_USAGE = 3;

    static ActivityResult create(int requestCode) {
        switch (requestCode) {
            case REQUEST_CODE_FOR_EVALUATION_SEND:
                return new ActivityResultEvaluationSend();
            case REQUEST_CODE_FOR_SMS_SEND_ACTIVITY:
                return new ActivityResultSmsSend();
            case REQUEST_CODE_FOR_CAMERA_USAGE:
                return new ActivityResultCameraUsage();// 他のコードについても同様
        }
    }

    abstract void complete(Activity activity);
}

class ActivityResultEvaluationSend extends ActivityResult {
    @Override
    public void complete(Activity activity) {
        activity.showToastMessage("評価を送信しました");
    }
}

class ActivityResultSmsSend extends ActivityResult {
    @Override
    public void complete(Activity activity) {
        activity.showToastMessage("SMS認証完了しました。");
    }
}

class ActivityResultCameraUsage extends ActivityResult {
    @Override
    public void complete(Activity activity) {
        activity.processPictureFromCamera();
    }
}

// ↓クライアントコード
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    ActivityResult result = ActivityResult.create(requestCode);
    result.complete(this);
}

ポリモーフィズムを使うことで、onActivityResult内の処理は綺麗になりました。
改修後は唯一出てくる条件分岐は、各種ActivityResultのサブクラスを生成するファクトリーメソッド内のみです。
オブジェクトの生成に条件分岐が出てくるだけなので、条件分岐かつそれぞれの処理内容も違った改修前よりは読みやすくなったと思います。

ただ一つ(エンジニア経験が浅い人間として)不安なのは、クラスをまたいだ処理が多くなるので、ソースを追うのがちょっと難しくなるなという点ですね。
このデメリットは設計のパターンが頭に入って入れば、補えるのかなと思いました。なので、勉強あるのみです。