すべてのクラスプロパティを持つコンストラクタまたはセッターを持つデフォルトコンストラクタ?

StackOverflow https://stackoverflow.com/questions/830657

  •  06-07-2019
  •  | 
  •  

質問

次の2つのアプローチがあります。

  • すべてのクラスプロパティを持つコンストラクタ

長所:正確な数のパラメーターを入力する必要があるため、エラーが発生した場合、コンパイラーから警告が表示されます(ところで、パラメーターリストで2つの整数を誤って切り替えたという問題を防ぐ方法はありますか? )

短所:プロパティがたくさんある場合、インスタンス化の行は非常に長くなる可能性があり、2行以上に及ぶ可能性があります

  • セッターとデフォルトの空のコンストラクター

長所:設定内容がはっきりとわかるので、何か間違ったことをしている場合は、入力すると同時にすぐに特定できます(2つの変数を切り替えるという前のエラーを作成することはできません)同じタイプ)

短所:多くのプロパティを持つオブジェクトのインスタンス化には数行かかる可能性があり(これが本当に短所かどうかはわかりません)、プロパティの設定を忘れるとコンパイラは何も言いません。

あなたは何をしますか、なぜですか? 提案するライトパターン(7+のプロパティを持つオブジェクトをインスタンス化するたびに使用する必要があると考えてください)を知っていますか? 私がこれを求めているのは、私が探している変数がどこにあるのかをすばやく把握できない大きなコンストラクタを嫌う傾向があるためです。一方で、「すべてのプロパティを設定する」一部のプロパティが欠落する脆弱性。

賛否両論は私の考えにすぎないので、私の仮定を自由に議論してください:)

更新-これに関連する私が見つけた質問:長いパラメータリストを持つコンストラクタを使用せずに大きな不変オブジェクトを構築する

役に立ちましたか?

解決

Joshua Blochが提唱し、 Effective Java で説明されているBuilderパターンを見ることができます。 http://developers.sunに主要なポイントに関するプレゼンテーションがあります。 .com / learning / javaoneonline / 2007 / pdf / TS-2689.pdf ;間違いなく、より良いリファレンスを掘り下げることができました。

基本的に、設定されるプロパティにちなんで名付けられたメソッドを提供し、呼び出しを連鎖できるように元のビルダーを返す別のクラス、おそらく内部クラスがあります。かなり読みやすいコードの塊になります。

たとえば、いくつかのプロパティを持つ単純な Message があるとします。これを構築するクライアントコードは、ビルダーを使用して次のように Message を準備できます。

Message message = new Message.Builder()
    .sender( new User( ... ) )
    .recipient( new User( ... ) )
    .subject( "Hello, world!" )
    .text( messageText )
    .build();

Message.Builder のフラグメントは、次のようになります。

public class Builder {

    private User sender = null;
    // Other properties

    public Builder sender( User sender ) {
        this.sender = sender;
        return this;
    }
    // Methods for other properties

    public Message build() {
        Message message = new Message();
        message.setSender( sender );
        // Set the other properties
        return message;
    }

}

他のヒント

大量のパラメーターを持つコンストラクターを持つ最大のプロを見逃しました:不変の型を作成できます。

不変のタイプを作成する通常の方法は、コンストラクターの巨大な厄介さを せずに、ヘルパーオブジェクトを作成することです。これは、最終オブジェクトに必要な値を保持する builder 準備ができたら不変オブジェクトを構築します。

APIのユーザビリティに関する最近の学術研究(CMUおよびMicrosoft)では、セッターを備えたデフォルトのコンストラクタがユーザビリティの観点から進むべき方法であることが示唆されています。 これは、「オブジェクトのコンストラクタにパラメータを要求することの有用性の意味」からです。ジェフ・スタイロスとスティーブン・クラークによって、ソフトウェア工学に関する国際会議で発表されました:

要約: APIの使いやすさは、プログラマの生産性にとってますます重要になっています。特定のAPIのユーザビリティ研究の経験に基づいて、多くのAPIに共通する設計選択のユーザビリティを研究するための手法が調査されました。パラメータなしの「デフォルト」とは対照的に、プロのプログラマーがオブジェクトのコンストラクターで必要なパラメーターを使用してAPIを使用する方法を評価するために、比較研究が行われました。コンストラクタ。必要なパラメーターは、オブジェクトの正しい使用とエラーの防止に向けてプログラマーを導くことにより、より使いやすく自己文書化されたAPIを作成すると仮定されました。ただし、この研究では、予想とは反対に、プログラマーはコンストラクターパラメーターを必要としないAPIを強く好み、より効果的であることがわかりました。参加者の行動は認知次元フレームワークを使用して分析され、必要なコンストラクターパラメーターが一般的な学習戦略に干渉し、望ましくない早すぎるコミットメントを引き起こすことが明らかになりました。

あなたはそれをあなたの投稿で言及していますが、これはより注目に値する重要なポイントだと思います:すべての入力パラメーターが異なるタイプでない限り、巨大なコンストラクターの大きな問題はそれが非常に簡単であるということですいくつかの変数を転置します。コンパイラは信頼性の低いセーフティネットです-いくつかの間違いをキャッチしますが、抜け落ちてしまうものを特定してデバッグするのははるかに困難になります。特に、別のウィンドウでAPIを開いていない限り、巨大なコンストラクターの入力リストは非常に不透明です。

ゲッターとセッターはデバッグが非常に簡単です。特に、オブジェクトに適切にデータが入力されていない場合にランタイム例外をスローするセーフガードを設定する場合はそうです。そして、私は「デバッグが簡単」の大ファンです。

このスレッドの前に、Robが言及したBuilderパターンについて聞いたことがありませんでした。自分で使用したことはありませんが(明らかに)、それは興味をそそられます。

前述の不変性の理由から、コンストラクター引数を取ることを好みます。それがあなたに多くの引数(例えば4つ以上)をとるコンストラクタを与えるなら、それは私にとってコード臭いです:それらの引数のいくつかはそれら自身の型にまとめられるべきです。

たとえば、次のようなものがある場合:

class Contact
{
    public Contact(string firstName, string lastName, string phoneNumber,
        string street, string city, string state, int zipCode) { ... }
}

リファクタリングします:

class Contact
{
    public Contact(Person person, PhoneNumber number, Address address) { ... }
}

class Person
{
    public Person(string firstName, string lastName) { ... }
}

class PhoneNumber
{
    public PhoneNumber(string digits) { ... }
}

class Address
{
    public Address(string street, string city, string state, int zipCode) { ... }
}

クラスが大きすぎることは、OOPコードベースでよくある設計上の問題です。

他の側面もあります。オブジェクトパレット(これはNetbeansを使用するJava)でオブジェクトとしてクラスを追加するなど、実行時だけでなく設計時にクラスで特定のことをできるようにしたい場合は、引数なしのコンストラクタを提供する必要がありますそうするために。

ここには他の戦略もあります。たくさんのパラメーターをどのように扱うかを理解しようとする前に、デザインを再検討し、クラスがやり過ぎであるかどうかを確認することが重要だと思います。いくつかのパラメーターを新しいクラスにグループ化できるかどうかを確認し、いくつかの動作をそのクラスに移動します。

  

セッターとデフォルトの空のコンストラクター

JRLが斜めに触れた、ただし、セッターの使用を検討する1つの理由は、オブジェクトを JavaBean仕様。これにより、インスタンスが編集特定のシリアル化手法を使用した、イントロスペクションツールおよび永続性経由/ a>。

どちらもできないと言うのは誰ですか?必須のプロパティはコンストラクターに入り、オプションのプロパティはセッターで処理されます。ところで、プロパティごとに常に1人のセッターが必要だと言う人はいますか?概念的に2つのプロパティが一緒に属する場合、一緒に設定してみませんか?

Builderパターンも好きですが、最も重要なルールは、常に頭脳を使用して、特定の問題に最適なデザインを見つけることです。万能のソリューションはありません。

scroll top