Pocket

ここでの内部クラスとは、次のようなinterface、class、enumです。SDKのクラスでこのような使い方を見かけるので、つい真似して、内部クラスを作ってみたくなります。

public class MyClass {
    public interface MyCallback {
        void run();
    }

    public static class MyParam {
        int x;
    }

    public enum MyType {
        START,
        STOP
    }

    private MyCallback myCallback;

    public void setListener(MyCallback myCallback) {
        this.myCallback = myCallback;
    }

    public void main(MyParam myParam, MyType myType) {
        System.out.println("main " + myParam.x);
        System.out.println("main " + myType);
        this.myCallback.run();
    }
}

MyClassを呼んでいるクライアント側のコードです。

        MyClass myClass = new MyClass();

        myClass.setListener(new MyClass.MyCallback() {
            @Override
            public void run() {
                System.out.println("MyCallback.run");
            }
        });

        MyClass.MyParam myParam = new MyClass.MyParam();
        myParam.x = 1;

        myClass.main(myParam, MyClass.MyType.START);

さて、MyClassを大きく修正するとき、MyClassはそのまま残しておき、MyClass2を作ることがよくあります。

MyClassとMyClass2をコメントなどで切り替えて、表示や動作をすぐに比較したいからです。場合によっては、両方とも表示することもあります。

MyClass2には内部クラスはなく、MyClassの内部クラス(MyClass.MyCallbackやMyClass.MyParamなど)を参照しています。

public class MyClass2 {
    private MyClass.MyCallback myCallback;

    public void setListener(MyClass.MyCallback myCallback) {
        this.myCallback = myCallback;
    }

    public void main(MyClass.MyParam myParam, MyClass.MyType myType) {
        System.out.println("MyClass2.main " + myParam.x);
        System.out.println(myType);
        this.myCallback.run();
    }
}

クライアント側は、new MyClass()の代わりに、new MyClass2()を挿入します。

        //MyClass myClass = new MyClass();
        MyClass2 myClass = new MyClass2();

        myClass.setListener(new MyClass.MyCallback() {
            @Override
            public void run() {
                System.out.println("MyCallback.run");
            }
        });

        MyClass.MyParam myParam = new MyClass.MyParam();
        myParam.x = 1;

        myClass.main(myParam, MyClass.MyType.START);

無事、MyClass2が完成し、MyClassのメソッドは未使用となったとき、MyClassをどのように編集すればいいでしょうか。

案1(☓)

そのまま残しておく。
→MyClassの全メソッドは未使用なので、間違いの元になります。

案2(☓)

MyClass2の新しいメソッド内容をMyClassへ移動して、MyClass2を削除する。→MyClassとMyClass2の比較バージョンにすぐに戻せません。

案3(△)

MyClassの内部クラスだけを残しておく。
→この経緯を知らない人は、なぜ、MyClassとMyClass2に分かれているんだろうと疑問に思います。

案4(△)

MyClassの内部クラスを、MyClass2に移動して、MyClassを削除する。
→MyClassとMyClass2の比較バージョンにすぐに戻せません。
→IDEのリファクタリング機能を使うと、クライアント側の編集作業は難しい作業ではありませんが、手作業が必要になるかもしれませんし、ビルドやテストが壊れるかもしれないです。あまりやりたい作業ではありません。

案1〜案4まで、どれもしっくりきません。強いて選ぶなら、案3です。

最初から、内部クラスにせず、それぞれを1ファイルにしておくと、

  • MyClassとMyClass2のファクトリークラスが作りやすいです。
  • MyClassが不要になったら、ファイルごとばっさり削除できます。
  • ファイル数が多くなることが気になるなら、別packageにしましょう。