web-dev-qa-db-ja.com

「getter setter」パターンを使用して、最初のアクセスで「setterメソッド」を呼び出し、残りの部分で「getterメソッド」を呼び出す最良の方法

これは、リクエストパラメータに含まれるjsonです。私は、jsonの値にアクセスするためのゲッターとセッターを持つクラスを構築しています。これにより、クラスオブジェクトをさまざまなメソッドに渡し、それらのメンバー変数にアクセスできるようになります。

public class RequestParams {
    private String student_id;
    private String student_name;
    private String student_role_number;
    private String department_name;
    private String stream;

    private JSONObject studentDetails;

    public RequestParams(HttpServletRequest request) {
        this.studentDetails = request.getParameter(“studentdetails”);
    }

    public String getStudentId() {
        if(this.student_id == null) {
            this.setStudentId();
        }
        return this.student_id;
    }
    public String getStudentName() {
        if(this.student_name == null) {
            this.setStudentName();
        }
        return this.student_name;
    }
    public String getRoleNumber() {
        if(this.student_role_number == null) {
            this.setRoleNumber();
        }
        return this.student_role_number;
    }
    public String getDepartmentName() {
        if(this.department_name == null) {
            this.setDepartmentName();
        }
        return this.student_name;
    }
    public String getStream() {
        if(this.stream == null) {
            this.setStream();
        }
        return this.stream;
    }
    public void setStudentId() {
        this.student_id = this.studentDetails.getString("student_id");
    }
    public void setStudentName() {
        this.student_name = this.studentDetails.getString("student_name");
    }
    public void setRoleNumber() {
        this.student_role_number = this.studentDetails.getString("role_number");
    }
    public void setDepartmentName() {
        this.department_name = this.studentDetails.getString("department_name");
    }
    public void setStream() {
        this.stream = this.studentDetails.getString("stream");
    }
}

次の疑問があります、

  1. 異なるメソッドから参照するためにクラスオブジェクトとして構築する-これは良いものですか?私は間違っていますか?
  2. Getter setterを整理して、setのみが初めて呼び出され、次の呼び出しで値が直接返されるようにする方法は?毎回nullチェックを回避するより良い方法はありますか

if(this.student_id == null){

this.setStudentId();

}

  1. this.を使用してクラス内のメソッドと変数にアクセスする利点はありますか?

PS:クラスで宣言されたすべての値が必ずしもjsonに存在する必要がないため、コンストラクターから最初にすべてのセッターを呼び出すことができませんでした。なので、最初のアクセス時にメンバー変数を値で初期化できればいいと思いました。

1
Tom Taylor

メンバー変数は冗長です。 JSONObjectまたはStringsのどちらかを保存する必要がありますが、両方を保存することはできません。これにより、一貫性の問題が回避されます。

ここに提案があります:

public class RequestParams {
    private final String student_id;
    private final String student_name;
    private final String student_role_number;
    private final String department_name;
    private final String stream;

    public RequestParams(HttpServletRequest request) {
        JSONObject studentDetails = request.getParameter(“studentdetails”);
        this.student_id = studentDetails.getString("student_id");
        this.student_name = studentDetails.getString("student_name");
        this.student_role_number = studentDetails.getString("role_number");
        this.department_name = studentDetails.getString("department_name");
        this.stream = studentDetails.getString("stream");
    }

    public String getStudentId() {
        return this.student_id;
    }
    public String getStudentName() {
        return this.student_name;
    }
    public String getRoleNumber() {
        return this.student_role_number;
    }
    public String getDepartmentName() {
       return this.student_name;
    }
    public String getStream() {
        return this.stream;
    }
}

メンバー変数をfinalにすることができ、クラスは不変であることに注意してください。

6
Frank Puffer

そのような初期化アプローチは と呼ばれます遅延初期化

遅延初期化は、オブジェクトの作成、値の計算、またはその他のコストのかかるプロセスを、最初に必要になるまで遅らせる戦術です。

一部の言語/プラットフォームは、このような構成(C#の Lazy<T> クラスなど)を表現する標準的な方法を提供しますが、他の言語/プラットフォームでは、独自に実装する必要があります/サードパーティを見つけるライブラリソリューション。

私が見る限り、Javaにはこのパターンの標準実装がないため、 シンプルなカスタムのもの を作成するか、 から使用できます。人気のあるサードパーティライブラリ

選択した遅延実装がLazy<T>と呼ばれるとすると、クラスは次のようになります。

public class RequestParams {
    private Lazy<String> student_id;

    private JSONObject studentDetails;

    public RequestParams(HttpServletRequest request) {
        this.studentDetails = request.getParameter(“studentdetails”);
        this.studentId = new Lazy<String>(() -> this.createStudentId());
    }

    public String getStudentId() {
        return this.student_id.value();
    }

    public String createStudentId() {
        return this.studentDetails.getString("student_id");
    }
}

PS:そのプリミティブなカスタムLazy<T>の実装を忘れないでください(この の背後にあるものと同様)link )は thread-safe ではないため、受け入れられる場合と受け入れられない場合があります。

PS1:また、コンストラクターのパラメーターとしてHttpServletRequestを使用するのがとても良い方法であるかどうかはよくわかりません。 RequestParamsはhttp関連のクラスを使用します。これにより、メンテナンスと単体テストが多少複雑になり、クラスの再利用の可能性が減少します。

PS2:Lazy<T>アプローチは適切な汎用ソリューションですが、この特定のケースでは、初期化が実際には比較的安価なので、むしろ@Frank Puffersuggestion に従い、コンストラクタでこのクラスを完全に初期化して、不変にします。

2
Eugene Podskal