2009-05-06 9 views
24

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

  • コンストラクタ

長所:私は、私は(コンパイラが私を警告するエラーを作るので、もしパラメータの種類の数を正確に配置する必要がありますところで、パラメータリストで2つのIntegerを間違って切り替えるという問題を防ぐ手段はありますか?)

短所:私は多くのプロパティを持っていると、インスタンス化の行が本当に長くなり、他の行

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

長所:(私ははっきりと私が設定してるかを見ることができますので、私は何か間違ったことをやっている場合、私はすぐに私はそれを入力していて、それを正確に特定することができます

短所:多くのプロパティを持つオブジェクトのインスタンス化には数行(実際にはconかどうかはわかりません)が必要です。if私はコンパイラが何も言わないプロパティを設定することを忘れています。

あなたは何をし、なぜですか? ライトパターンを知っていますか(7+プロパティがインスタンス化されるたびに使用する必要があると考えていますか?) 私は、私が探している変数がどこにあるのかわからない大規模なコンストラクタを嫌う傾向があるため、これを求めています。一方、「すべてのプロパティを設定する」は、 。

彼らは唯一の鉱山の考え:)

更新されているとして、賛否両論の私の仮定の引数に気軽 - これに関連している私が見つけた質問:Building big, immutable objects without using constructors having long parameter lists

答えて

20

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; 
    } 

} 
+0

説明コードありがとう –

+0

複雑なオブジェクトを持っていれば、ビルダーは本当に素晴らしいです。私は強くそれをお勧めすることができます。 –

+0

と本!これは、Javaプログラマにとって本当に必要なものです。私はそれを読んでいます(私たちはそれを読んでいます) –

26

あなたが見逃しています多くのパラメータを持つコンストラクタを持つことの最大の利点は、不変型を作成できることです。

巨大なコンストラクタ意地の悪させずに不変の種類を作成する通常の方法は、ヘルパータイプすることです - あなたはあなたの最終的なオブジェクトにたいと思う値を維持ビルダーを、そしてあなたがしている不変オブジェクトを構築します準備ができました。

+0

とにかくビルダーは、より良い戦略ではありませんか? – Uri

+0

さらに、オブジェクトの状態がプロパティが設定されていない状態で実行できない場合は、コンストラクタを経由してオブジェクトを設定するように強制します。 –

+0

@Uri:あなたはいくつかのプロパティを持っている場合は、ビルダーのパターンは上のIMO上です。 –

6

APIのユーザビリティに関する最近の学術研究(CMUとMicrosoft)は、セッターを持つデフォルトのコンストラクタがユーザビリティの観点から考える方法であることを示唆しています。 これはジェフSTYLOSとスティーブン・クラークによる「Objectsのコンストラクタのパラメータが必要なの使いやすさへの影響」からのものであり、ソフトウェア工学に関する国際会議で発表されました:

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

0

。実行時だけではなく、設計時にクラスで特定のことをできるようにしたい場合、たとえばクラスをオブジェクトパレット(Netbeansを使用するJava)としてオブジェクトとして追加する場合は、引数なしのコンストラクタをそうすることができるようにする。

+0

これは重要な考慮事項です - ORMツール(Hibernateなど)は、最新のバージョンであればわかりませんが、アクセス可能なセッターとデフォルトのコンストラクターを必要とする傾向があります。 – hromanko

3

これはあなたの投稿に記載されていますが、これはもっと重要なポイントです:すべての入力パラメータが異なるタイプでなければ、巨大なコンストラクタの大きな問題はそれです非常に変数のコンパイラーは信頼性の低い安全ネットであり、いくつかの間違いを犯しますが、スリップするものは識別してデバッグするのがはるかに難しくなります。特に、巨大なコンストラクタの入力リストは、別のウィンドウでAPIを開いていない限り、非常に不透明です。

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

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

+0

オブジェクトが正しく設定されていない場合、実行時例外をスローするセーフガードをどのように確立するのですか? – mayu

0

他の戦略もあります。多くのパラメータを処理する方法を理解する前に、デザインを再訪問し、クラスがあまりにも多くを行っているかどうかを調べることが重要だと思います。いくつかのパラメータをまとめて新しいクラスにまとめることができるかどうかを確認し、そのクラスにいくつかの動作を移してください。

2

上記の不変の理由から、コンストラクタの引数を取ることをお勧めします。それが引数をたくさん取るコンストラクタ(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のコードベースでは本当に一般的な設計上の問題です。

+0

どのようにzipCodeをオプションで扱うのですか? –

+0

オーバーロードアドレスのコンストラクタです。 – munificent

0

誰もあなたは両方を行うことはできないと言いますか?私は必須のプロパティがコンストラクタに入り、オプションのものはセッターで処理されると言っています。あなたはいつも、プロパティごとに1つのセッターが必要だと言う人はいますか? 2つのプロパティが概念的に属している場合は、それらを一緒に設定しないでください。

私はBuilderパターンも気に入っていますが、最も重要なルールは、常にあなたの脳を使い、特定の問題に最も適したデザインを見つけることです。サイズに合わせたソリューションはありません。

関連する問題