再利用可能なオブジェクトの抽象メソッドとインスタンス変数


8

再利用できるように手直ししているJavaコードがかなりあります。問題は、プロジェクト固有の部分が多く、アプリケーションプロジェクトとコードベースプロジェクト間の結合のレベルが高くなることです。

抽象メソッドの使用を実装するクラスを使用して子クラスからリソースを取得する以下の状況と、インスタンス変数を宣言するだけの状況と比較してください。

抽象メソッド:

public abstract class SuperBaseClass {

    public abstract int getNumberOne();
    public abstract String getStringOne();
    public abstract String getStringTwo();

    public printStuff() {
        Log.i("IntAndTwoStrings", String.format("%i %s and %s",
                            getNumberOne(), getStringOne(), getStringTwo()));
    }

}

public class ReusedAppClass extends SuperBaseClass {

    public int getNumberOne() {
        return 1;
    }
    public String getStringOne() {
        return "String1";
    }
    public String getStringTwo() {
        return "String2";
    }

    public ReusedAppClass() {
        printStuff();
    }

}

インスタンス変数:

public class SuperBaseClass {

    protected int numberOne;
    protected String stringOne;
    protected String stringTwo;

    public printStuff() {
        //Possibly throw RuntimeExceptions if the app didnt set these
        Log.i("IntAndTwoStrings", String.format("%i %s and %s",
                            numberOne, stringOne, stringTwo));
    }

}

public class ReusedAppClass extends SuperBaseClass {

    public ReusedAppClass() {
        numberOne = 1;
        stringOne = "String1";
        stringTwo = "String2";
        printStuff();
    }

}

トレードオフはありますか?抽象メソッドの状況は行き過ぎですか、それとも抽象クラスが作成されたのですか?

回答:


8

抽象メソッドがより良い選択だと思います。これらのプロパティの実装が、サブクラスで心配する必要のないものである場合は、基本クラスに責任を持たせることもできます。つまり、パブリックアクセサーと保護されたミューテーターで基本クラスのプライベートフィールドを使用します。

public class SuperBaseClass {

    private int numberOne;
    private String stringOne;
    private String stringTwo;

    public int getNumberOne() { return numberOne; }
    public String getStringOne() { return stringOne; }
    public String getStringTwo() { return stringTwo; }

    protected void setNumberOne(String numberOne) { this.numberOne = numberOne; }
    protected void setStringOne(String stringOne) { this.stringOne = stringOne; }
    protected void setStringTwo(String stringTwo) { this.stringTwo = stringTwo; }

    public printStuff() {
        Log.i("IntAndTwoStrings", String.format("%i %s and %s", getNumberOne(), getStringOne(), getStringTwo()));
    }
}

この種類のアプローチは、強力なカプセル化を提供します。つまり、フィールドを直接変更できるコードの量が最小限に抑えられます。


より良いカプセル化は、抽象メソッドを使用することの明確な利点です+1
Styler

5

抽象クラスアプローチでは、拡張クラスが変数を「初期化」するように強制しますが、保護されたインスタンス変数を使用すると、デフォルトを簡単に使用して、拡張しないと混乱/バグを引き起こす可能性があります。


3

私見より良いアプローチは、いくつかのフィールドをカスタマイズするためだけの場合は、構成を使用し、継承を完全に回避することです。「子クラスからリソースを取得するには」と言うので、次のようにします。

public class MyResources() {

private int numberOne;
private String stringOne;
private String stringTwo;

public int getNumberOne() {
    return numberOne;
}

public void setNumberOne(int numberOne) {
    this.numberOne = numberOne;
}

public String getStringOne() {
    return stringOne;
}

public void setStringOne(String stringOne) {
    this.stringOne = stringOne;
}

public String getStringTwo() {
    return stringTwo;
}

public void setStringTwo(String stringTwo) {
    this.stringTwo = stringTwo;
}
}

次に、クラスでMyResourcesオブジェクトをインスタンス化し、必要に応じてそれらをカスタマイズします。それでもクラスの階層が必要な場合は、基本クラスにリソースオブジェクトを置き、それを子クラスに継承できます。

public abstract class SuperBaseClass {

protected MyResources resources;

public SuperBaseClass() {
    resources.setStringOne("Hello");
}

public class ReusedAppClass extends SuperBaseClass {

public ReusedAppClass () {
    super();
    resources.setStringOne("Hi");
}
}

2

これらのすべての変数が基本クラスのプロパティであり、子がそれらに一様に依存している場合は、基本でそれらを宣言することが適切であり、抽象get / setters / accessorsを追加することは、子供がデータを適切にマッサージできるようにする方法です。これは決してやり過ぎではなく、OOPはこれらの種類の関係を表現するように設計されています。

この種のデータをベースクラスに送りすぎていることがわかった場合(または、このデータがすべての子に普遍的に共通しているわけではない場合)、ベースクラスをコンテナにリファクタリングする時期が来るかもしれません。ロジックとコードの整理に役立つ、より具体的な基本クラス。これはもう少し複雑になりますが、よりすっきりとした設計が可能になり、適切な名前を付けると、わかりやすくなります。

私のどちらの場合でも、物事を変更する前に、最初に再利用すると予想されることを正確に分析する必要があります。既存のコードから再利用可能なフレームワークを作成することは、データの再編成やそのモジュールでの再利用などのためにそのデータに対する操作を行うこととはまったく異なる場所になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.