2

コンストラクターでクラスの set メソッドを使用して、初期化する値をチェックし、設定した制約に準拠していない場合は例外をスローしたいと考えています。

コード例:

public class MyClass {

    // Fields
    private int number;
    private String string;

    // Constructor
    public MyClass(int number, String string) {
        setNumber(number);
        setString(string);
    }

    // Set Methods
    public void setNumber(int number) {
        if (number<=0) {    // Certain constrain for number
            throw new IllegalArgumentException("Number must be positive");
        }
        this.number = number;
    }

    public void setString(String string) { // Certain constrain for string
        if (string.equals("")) {
            throw new IllegalArgumentException("string cannot be empty");
        } 
        this.string = string;
    }

    public String toString() {
        return String.format("Ordered %d x %s%n", number, string);
    }

    public static void main(String[] args) {
        MyClass obj = new MyClass(8, "Souvlaki");   // Everything allright
        System.out.println(obj);
        try {
            MyClass obj2 = new MyClass(-3, "Mousaka");  // Error in number argument
        } catch (IllegalArgumentException exception) {  // catch the exception
            System.out.printf("Exception Caught: Number must be positive%n%n");
        }
        MyClass obj2 = new MyClass(4, "");  // Error in string argument
        // Allow the exception to end program execution
    }
}

出力:

8 x スブラキを注文

キャッチされた例外: 数値は正でなければなりません

スレッド「メイン」の例外 java.lang.IllegalArgumentException: MyClass.main(MyClass.java:40) の MyClass.(MyClass.java:10) の MyClass.setString(MyClass.java:23) で文字列を空にすることはできません

出力はまさに私が望んでいたものです。最初に作成されたオブジェクトは、適切な値で初期化されます。toString() メソッドを呼び出すと、暗黙的にそれが証明されます。2 番目と 3 番目のオブジェクトは、初期化が間違っているために例外をスローします。プログラムの実行を継続できるようにするために、最初の例外がキャッチされます。2 番目の例外は、例外として出力されるエラー メッセージを出力するためにキャッチされません。

すべてが正しいように見えますが、これは優れたプログラミング手法ですか、それとも内部にいくつかのバグを隠していますか?

4

3 に答える 3

4

コメントが示唆するように、それに問題がある可能性があります。特に、コンストラクターでのオーバーライド可能なメソッド呼び出しの何が問題になっているのかを確認することをお勧めします。. 要点は大まかに: 誰かがset...予期しない方法でメソッドをオーバーライドし、クラスの他の (初期化されていない) フィールドを参照する可能性があり、あらゆる種類のバグを引き起こす可能性があります。

専用の検証方法がオプションの場合があります。ただし、検証が必要ない場合でも、これらは複数回呼び出される場合があります。

set...メソッドを作成することで、ほとんどの問題を軽減できますfinal。とにかくこれは良い習慣です。Joshua Bloch が彼の著書「Effective Java」で述べているように、項目 17:

「継承またはそれを禁止するための設計および文書化」

これは、明示的にオーバーライドを許可したい場合を除き、すべてのメソッドを作成し、オーバーライド方法を文書化する (または、代わりにクラス全体を作成する) 必要があることを意味します。finalfinal

于 2015-03-15T11:29:28.137 に答える
0

変数はクラス内のどこからでもアクセスできるため、ミューテーター メソッドを使用して変数を初期化する必要はありません。

入力パラメーターで何らかの検証を行う場合は、必要なすべての検証を実行する別の方法を使用してください。

コンストラクターで検証メソッドを呼び出します。

于 2015-03-15T10:45:10.737 に答える
0

コンストラクターで検証を行うのではなく、checkInvariant()すべてのフィールドを検証するメソッドをクラスで作成できます。

class MyClass {
    private int num;
    private String value;

    public void checkInvariants() {
        assertNotEmpty(value, "String value cannot be empty");
        assertPositive(num, "Number num should be non-negative");
    }
}

そして、このクラスのインスタンスを引数として渡す可能性のある別の場所で、最初にこのメソッドを呼び出して、不変条件が確実に保持されるようにします。

class SomeOtherClass {
    public void doSomethingWithMyClass(MyClass myClass) {
        myClass.checkInvariants();
        // Proceed with work.
    }
}
于 2015-03-15T09:58:21.917 に答える