(6+)パラメータが多すぎるメソッドをリファクタリングする最良の方法は何ですか?


102

ときどき、不快な数のパラメーターを持つメソッドに遭遇します。多くの場合、それらはコンストラクターのようです。より良い方法があるべきだと思われますが、それが何であるか私にはわかりません。

return new Shniz(foo, bar, baz, quux, fred, wilma, barney, dino, donkey)

私は構造体を使用してパラメーターのリストを表すことを考えましたが、それは問題をある場所から別の場所に移し、その過程で別のタイプを作成するようです。

ShnizArgs args = new ShnizArgs(foo, bar, baz, quux, fred, wilma, barney, dino, donkey)
return new Shniz(args);

そのため、改善のようには見えません。それで、最善のアプローチは何ですか?


あなたは「構造」と言いました。その用語は、プログラミング言語によって意味が異なります。どういう意味ですか?
ジェイバズジ2009年

1
特定の言語を明確にするために探している場合は、C#を使用してください。しかし、基本的には、単なるプロパティバッグです。異なるタイプの異なる名前付きプロパティがあります。クラス、ハッシュテーブル、構造体などとして定義できます。
再帰

この記事には、このトピックに関するいくつかの良い洞察があります。JavaScript固有ですが、原則は他の言語にも適用できます。
lala

回答:


94

最善の方法は、引数をグループ化する方法を見つけることです。これは、引数の「グループ化」が複数になることを想定しており、実際にのみ機能します。

たとえば、長方形の仕様を渡す場合、x、y、幅、および高さを渡すことができます。あるいは、x、y、幅、および高さを含む長方形オブジェクトを渡すこともできます。

ある程度クリーンアップするためにリファクタリングするときは、このようなものを探してください。議論を本当に組み合わせることができない場合は、単一責任原則に違反しているかどうかを調べ始めます。


4
良い考えだが悪い例。Rectangleのコンストラクタには4つの引数が必要です。これは、メソッドが2組の長方形の座標/寸法を想定している場合に、より意味があります。次に、x1、x2、y1、y2の代わりに2つの長方形を渡すことができます...
Outlaw Programmer

2
けっこうだ。私が言ったように、実際に複数の論理グループになってしまう場合にのみ意味があります。
マシューBrubaker

23
+1:単一の責任へ、それは真の問題を実際に扱っているすべての回答における数少ないコメントの1つです。アイデンティティを形成するために7つの独立した値が本当に必要なオブジェクトはどれですか。
AnthonyWJones 2009年

6
@AnthonyWJones同意しない。現在の気象条件のデータは、そのアイデンティティを形成するために、さらに多くの独立した値を持つことができます。
funct7 2017年

107

私はあなたがC#を意味すると仮定します。これらのいくつかは他の言語にも当てはまります。

いくつかのオプションがあります。

コンストラクターからプロパティセッターに切り替えます。これにより、どの値がどのパラメーターに対応するかが読者に明らかになるため、コードが読みやすくなります。オブジェクト初期化構文は、これを見栄えよくします。自動生成されたプロパティを使用して、コンストラクターの作成をスキップできるため、実装も簡単です。

class C
{
    public string S { get; set; }
    public int I { get; set; }
}

new C { S = "hi", I = 3 };

ただし、不変性が失われ、コンパイル時にオブジェクトを使用する前に必要な値が設定されていることを確認できなくなります。

ビルダーパターン

stringとの関係について考えてくださいStringBuilder。あなたはあなた自身のクラスのためにこれを得ることができます。ネストされたクラスとして実装したいので、クラスにCは関連クラスがありC.Builderます。また、ビルダーの流暢なインターフェースも気に入っています。正しく実行すると、次のような構文を取得できます。

C c = new C.Builder()
    .SetX(4)    // SetX is the fluent equivalent to a property setter
    .SetY("hello")
    .ToC();     // ToC is the builder pattern analog to ToString()

// Modify without breaking immutability
c = c.ToBuilder().SetX(2).ToC();

// Still useful to have a traditional ctor:
c = new C(1, "...");

// And object initializer syntax is still available:
c = new C.Builder { X = 4, Y = "boing" }.ToC();

これを行うためのビルダーコードを生成できるPowerShellスクリプトがあります。入力は次のようになります。

class C {
    field I X
    field string Y
}

したがって、コンパイル時に生成できます。 partialクラスを使用すると、生成されたコードを変更せずに、メインクラスとビルダーの両方を拡張できます。

「パラメーターオブジェクトの導入」リファクタリングリファクタリングカタログを参照してください。考えているのは、渡すパラメーターのいくつかを取り、それらを新しい型に入れて、代わりにその型のインスタンスを渡すというものです。何も考えずにこれを行うと、開始した場所に戻ってしまいます。

new C(a, b, c, d);

なる

new C(new D(a, b, c, d));

ただし、このアプローチには、コードに良い影響を与える可能性が最も高くなります。したがって、次の手順に従ってください。

  1. 一緒に意味のあるパラメーターのサブセットを探します。関数のすべてのパラメーターをうっかりグループ化しても、あまり効果はありません。目標は、意味のあるグループ分けをすることです。 新しいタイプの名前が明らかな場合は、正しく理解できます。

  2. これらの値が一緒に使用されている他の場所を探し、そこでも新しいタイプを使用してください。その場所全体で既に使用している一連の値に適した新しい型を見つけた場合、その新しい型はすべての場所で意味をなす可能性があります。

  3. 既存のコードに含まれているが、新しいタイプに属している機能を探します。

たとえば、次のようなコードが表示される場合があります。

bool SpeedIsAcceptable(int minSpeed, int maxSpeed, int currentSpeed)
{
    return currentSpeed >= minSpeed & currentSpeed < maxSpeed;
}

minSpeedmaxSpeedパラメータを取り、それらを新しいタイプに入れることができます:

class SpeedRange
{
   public int Min;
   public int Max;
}

bool SpeedIsAcceptable(SpeedRange sr, int currentSpeed)
{
    return currentSpeed >= sr.Min & currentSpeed < sr.Max;
}

これはより良い方法ですが、新しいタイプを実際に利用するには、比較を新しいタイプに移動します。

class SpeedRange
{
   public int Min;
   public int Max;

   bool Contains(int speed)
   {
       return speed >= min & speed < Max;
   }
}

bool SpeedIsAcceptable(SpeedRange sr, int currentSpeed)
{
    return sr.Contains(currentSpeed);
}

そして今、私たちはどこかに着いています:SpeedIsAcceptable()今の実装はあなたが何を意味するかを言い、あなたは便利で再利用可能なクラスを持っています。(次の明白なステップは、を作るSpeedRangeことRange<Speed>です。)

ご覧のとおり、パラメータオブジェクトの導入は良い出発点でしたが、その真の価値は、モデルから欠落している有用な型を発見するのに役立つことでした。


4
最初に「パラメータオブジェクトの導入」を試し、作成する適切なパラメータオブジェクトが見つからない場合にのみ、他のオプションにフォールバックすることをお勧めします。
ダグラスリーダー2009年

4
すばらしい答え。c#構文糖の前にリファクタリングの説明を述べた場合、これはより高いIMHOに投票されたでしょう。
rpattabi 2010年

10
おお!+1「新しいタイプの名前が明らかな場合は、正しく理解できているはずです。」
Sean McMillan

20

それがコンストラクターである場合、特に複数のオーバーロードされたバリアントがある場合は、Builderパターンを確認する必要があります。

Foo foo = new Foo()
          .configBar(anything)
          .configBaz(something, somethingElse)
          // and so on

それが通常のメソッドである場合は、渡される値間の関係について考え、おそらく転送オブジェクトを作成する必要があります。


素晴らしい返事。おそらく、(私を含む)全員が与えた「クラスにパラメーターを置く」という応答よりもさらに関連性があります。
Wouter Lievens、

1
コンストラクターに渡されるパラメーターが多すぎないようにするためだけにクラスを変更可能にするのは、おそらく悪い考えです。
アウトロープログラマ、

@outlaw-可変性が懸念される場合、「1回だけ実行」のセマンティクスを簡単に実装できます。ただし、多数のctorパラメータはしばしば構成の必要性を示します(または、他の人が指摘しているように、クラスが多すぎることを実行しようとしています)。(続き)
kdgregory 2009年

構成を外部化することもできますが、多くの場合、特にプログラムの状態によって駆動される場合や、特定のプログラムの標準である場合は不要です(XMLパーサーは、名前空間に対応しており、さまざまなツールで検証できます&c)。
kdgregory 2009年

私はビルダーパターンが好きですが、string / StringBuilderのように、不変と可変のビルダータイプを分離していますが、ネストされたクラスFoo / Foo.Builderを使用しています。単純なデータクラスに対してこれを行うためのコードを生成するPowerShellスクリプトがあります。
Jay Bazuzi、2009年

10

これに対する典型的な答えは、クラスを使用して一部またはすべてのパラメーターをカプセル化することです。理論的には素晴らしいように聞こえますが、私はこの分野で意味を持つ概念のクラスを作成するような人なので、このアドバイスを適用するのは必ずしも容易ではありません。

例:

driver.connect(host, user, pass)

あなたは使うことができます

config = new Configuration()
config.setHost(host)
config.setUser(user)
config.setPass(pass)
driver.connect(config)

YMMV


5
私は間違いなく最初のコードをもっと欲しいです。私は、いくつかの制限があることに同意します。これを超えると、numf rofパラメータが醜くなりますが、私の好みでは、3が許容範囲です。
blabla999 2009年

10

これは、Fowler and Beckの本「リファクタリング」から引用されています。

長いパラメータリスト

プログラミングの初期の頃には、ルーチンに必要なすべてのものをパラメータとして渡すように教えられていました。代替案はグローバルデータであり、グローバルデータは悪であり、通常は苦痛であるため、これは理解できました。オブジェクトがこの状況を変えるのは、必要なものがなければ、いつでも別のオブジェクトにそれを取得するように依頼できるためです。したがって、オブジェクトでは、メソッドが必要とするすべてのものを渡すわけではありません。代わりに、メソッドが必要なすべてのものに到達できるように、十分に渡します。メソッドが必要とするものの多くは、メソッドのホストクラスで利用できます。オブジェクト指向プログラムでは、パラメーターリストは従来のプログラムよりもはるかに小さくなる傾向があります。長いパラメーターリストは一貫性がなく使いにくくなるため、理解しにくいため、これは良いことです。さらに多くのデータが必要になると、それらを永久に変更するためです。ほとんどの変更は、オブジェクトを渡すことによって削除されます。これは、新しいデータを取得するために2、3回のリクエストを行う必要がある可能性がはるかに高いためです。既に知っているオブジェクトをリクエストして1つのパラメータのデータを取得できる場合は、パラメータでメソッドを置換を使用します。このオブジェクトはフィールドの場合もあれば、別のパラメーターの場合もあります。オブジェクト全体を保持を使用して、オブジェクトから収集した大量のデータを取得し、それをオブジェクト自体で置き換えます。論理オブジェクトのないデータ項目がいくつかある場合は、パラメーターオブジェクトの導入を使用します。これらの変更を行うには、1つの重要な例外があります。これは、呼び出されたオブジェクトから大きなオブジェクトへの依存関係を明示的に作成したくない場合です。これらの場合、データをアンパックしてパラメーターとして送信することは妥当ですが、それに伴う苦痛に注意してください。パラメータリストが長すぎるか、頻繁に変更される場合は、依存関係の構造を再考する必要があります。


7

私は賢明な亀裂のように聞こえたくありませんが、渡すデータが本当に渡されることを確認することも確認する必要があります。オブジェクトの動作にはほとんど重点を置きません。

誤解しないでください。メソッドとコンストラクターは、多くのパラメーターが含まれることがあります。ただし、問題が発生した場合は、代わりに動作を伴うデータのカプセル化を検討してください。

この種類のにおい(リファクタリングについて話しているので、この恐ろしい言葉は適切だと思われます...)は、多くの(読み取り:任意の)プロパティまたはゲッター/セッターを持つオブジェクトでも検出される可能性があります。


7

長いパラメーターリストが表示されたときの最初の質問は、この関数またはオブジェクトが実行しすぎているかどうかです。検討してください:

EverythingInTheWorld earth=new EverythingInTheWorld(firstCustomerId,
  lastCustomerId,
  orderNumber, productCode, lastFileUpdateDate,
  employeeOfTheMonthWinnerForLastMarch,
  yearMyHometownWasIncorporated, greatGrandmothersBloodType,
  planetName, planetSize, percentWater, ... etc ...);

もちろん、この例はわざとばかげていますが、実際のプログラムの多くは、ほんの少しばかげているだけの例で見ました。1つのクラスを使用して、ほとんど関係のない、または関係のない多くのものを保持しています。プログラマーはたまたま両方を同時に考えました。時々簡単な解決策は、クラスを複数の部分に分割することです。それぞれが独自のことを行います。

やや複雑なのは、クラスが実際に顧客の注文と顧客に関する一般的な情報の両方など、複数の論理的なものを処理する必要がある場合です。このような場合は、お客様用のクラスと注文用のクラスを作成し、必要に応じて会話させてください。だから代わりに:

 Order order=new Order(customerName, customerAddress, customerCity,
   customerState, customerZip,
   orderNumber, orderType, orderDate, deliveryDate);

次のことができます。

Customer customer=new Customer(customerName, customerAddress,
  customerCity, customerState, customerZip);
Order order=new Order(customer, orderNumber, orderType, orderDate, deliveryDate);

もちろん、私は1つ、2つ、または3つのパラメーターをとる関数を好みますが、現実的にはこの関数は一群であり、それ自体の数が実際に複雑さを生み出さないことを受け入れる必要があります。例えば:

Employee employee=new Employee(employeeId, firstName, lastName,
  socialSecurityNumber,
  address, city, state, zip);

ええ、それはたくさんのフィールドですが、恐らく私たちがフィールドでやろうとしていることは、それらをデータベースレコードに保存するか、画面などに投げることだけです。ここでは実際には多くの処理は行われません。

パラメータリストが長くなる場合は、フィールドにさまざまなデータ型を指定できるかどうかを考えます。私が次のような関数を見たときのように:

void updateCustomer(String type, String status,
  int lastOrderNumber, int pastDue, int deliveryCode, int birthYear,
  int addressCode,
  boolean newCustomer, boolean taxExempt, boolean creditWatch,
  boolean foo, boolean bar);

そして、私はそれが次のように呼ばれるのを見ます:

updateCustomer("A", "M", 42, 3, 1492, 1969, -7, true, false, false, true, false);

心配になります。呼び出しを見て、これらすべての不可解な数字、コード、およびフラグが何を意味するのかは、まったく明確ではありません。これはエラーを要求するだけです。プログラマーはパラメーターの順序について混乱し、誤って2つを切り替えてしまう可能性があり、それらが同じデータ型であれば、コンパイラーはそれを受け入れるだけです。私はむしろこれらすべてが列挙型であるシグネチャを持っているので、呼び出しは「A」の代わりにType.ACTIVEや「false」の代わりにCreditWatch.NOなどのように渡されます。


5

コンストラクターのパラメーターの一部がオプションである場合は、ビルダーを使用して、コンストラクターで必要なパラメーターを取得し、オプションのパラメーターのメソッドを使用してビルダーを返し、次のように使用することは理にかなっています。

return new Shniz.Builder(foo, bar).baz(baz).quux(quux).build();

この詳細は、Effective Java、2nd Ed。、p。11.メソッドの引数については、同じ本(p。189)で、パラメーターリストを短縮するための3つのアプローチについて説明しています。

  • メソッドを引数の少ない複数のメソッドに分割する
  • パラメータのグループを表す静的ヘルパーメンバークラスを作成します。つまりDinoDonkeydinoし、donkey
  • パラメーターがオプションの場合、上記のビルダーをメソッドに採用し、すべてのパラメーターのオブジェクトを定義し、必要なパラメーターを設定して、その上でいくつかの実行メソッドを呼び出すことができます。

4

デフォルトのコンストラクターとプロパティセッターを使用します。C#3.0には、これを自動的に行うための優れた構文があります。

return new Shniz { Foo = foo,
                   Bar = bar,
                   Baz = baz,
                   Quuz = quux,
                   Fred = fred,
                   Wilma = wilma,
                   Barney = barney,
                   Dino = dino,
                   Donkey = donkey
                 };

コードの改善は、コンストラクターを単純化し、さまざまな組み合わせをサポートするために複数のメソッドをサポートする必要がないことをもたらします。「呼び出し」構文は、まだ少し「複雑」ですが、プロパティセッターを手動で呼び出すよりも実際には最悪ではありません。


2
これにより、新しいShniz()のオブジェクトが存在できるようになります。優れたOO実装は、オブジェクトが不完全な状態で存在する可能性を最小限に抑えることを目指します。
AnthonyWJones 2009年

一般に、ネイティブハッシュ/辞書構文を使用する言語には、名前付きパラメーターの適切な代替が付属しています(これらは、これらの状況で必要とされる素晴らしいものですが、何らかの理由で、それらをサポートする唯一の一般的な言語が地球上で最悪のものです)。 。
混沌

4

良い答えを保証するのに十分な情報が提供されていません。パラメータリストが長いことは、本質的に悪いことではありません。

Shniz(foo、bar、baz、quux、fred、wilma、barney、dino、donkey)

次のように解釈できます:

void Shniz(int foo, int bar, int baz, int quux, int fred, 
           int wilma, int barney, int dino, int donkey) { ...

この場合、コンパイラーがコードをチェックし、視覚的にコードを読みやすくできるようにさまざまなパラメーターに意味を与えるため、パラメーターをカプセル化するクラスを作成する方がはるかに適切です。また、後で読みやすく、リファクタリングも簡単になります。

// old way
Shniz(1,2,3,2,3,2,1,2);
Shniz(1,2,2,3,3,2,1,2); 

//versus
ShnizParam p = new ShnizParam { Foo = 1, Bar = 2, Baz = 3 };
Shniz(p);

または、次の場合:

void Shniz(Foo foo, Bar bar, Baz baz, Quux quux, Fred fred, 
           Wilma wilma, Barney barney, Dino dino, Donkey donkey) { ...

すべてのオブジェクトが異なる(そして混乱する可能性が低い)ため、これはまったく異なるケースです。すべてのオブジェクトが必要であり、それらがすべて異なる場合、パラメータークラスを作成してもほとんど意味がないことに同意します。

さらに、一部のパラメーターはオプションですか?そこにメソッドのオーバーライドの(同じメソッド名が、別のメソッドのシグネチャ?)詳細のこれらの種類は何にように、すべての問題で最良の答えはあります。

*プロパティバッグも役立ちますが、背景が指定されていないため、特に良いとは言えません。

ご覧のとおり、この質問には1つ以上の正解があります。好きなのを選びな。



2

私は一般的に構造体アプローチに傾いています-おそらくこれらのパラメーターの大部分は何らかの方法で関連しており、あなたのメソッドに関連するいくつかの要素の状態を表しています。

パラメータのセットを意味のあるオブジェクトにすることができない場合、それShnizはおそらく、やりすぎの兆候であり、リファクタリングには、メソッドを個別の問題に分解する必要があります。


2

複雑さをソースコードの行と交換できます。メソッド自体が多すぎる場合(スイスナイフ)、別のメソッドを作成してタスクを半分にしてください。メソッドが単純で、必要なパラメーターが多すぎる場合は、いわゆるパラメーターオブジェクトが適しています。


2

言語でサポートされている場合は、名前付きパラメーターを使用して、可能な限り多くのオプション(適切なデフォルトで)を指定します。


1

あなたが説明した方法が進むべき道だと思います。多くのパラメーターを持つメソッドや将来さらに必要となる可能性の高いメソッドを見つけたときは、通常、通過するShnizParamsオブジェクトを作成します。


1

コンストラクタで一度に設定するのではなく、プロパティ/セッターを使用して設定してみませんか?クラスなど、このアプローチを利用するいくつかの.NETクラスを見てきましたProcess

        Process p = new Process();

        p.StartInfo.UseShellExecute = false;
        p.StartInfo.CreateNoWindow = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.FileName = "cmd";
        p.StartInfo.Arguments = "/c dir";
        p.Start();

3
C#3には、これを簡単に行うための構文があります。オブジェクト初期化子です。
ダレン・トーマス

1

パラメーターをパラメーターオブジェクト(構造体)に移動する方法に同意します。ただし、すべてを1つのオブジェクトに固定するのではなく、他の関数が同様のパラメーターのグループを使用しているかどうかを確認します。パラメータオブジェクトが複数の関数で使用され、パラメータセットがそれらの関数全体で一貫して変化することが期待される場合、paramaterオブジェクトはより価値があります。一部のパラメーターのみを新しいパラメーターオブジェクトに配置している可能性があります。


1

パラメータの数が多い場合は、メソッドの処理が多すぎる可能性があるため、まずメソッドをいくつかの小さなメソッドに分割して対処します。この後もパラメーターが多すぎる場合は、引数をグループ化するか、一部のパラメーターをインスタンスメンバーに変えてみてください。

大きいクラスよりも小さいクラス/メソッドを優先します。単一責任の原則を思い出してください。


インスタンスのメンバーとプロパティの問題は、1)書き込み可能でなければならない、2)設定されていない可能性があることです。コンストラクターの場合、インスタンスの存在を許可する前に確実に入力したい特定のフィールドがあります。
再帰

@recursive-フィールド/プロパティは常に書き込み可能でなければならないことに同意しません。少人数のクラスの場合、読み取り専用メンバーが理にかなっていることがよくあります。
ブライアンラスムッセン

1

名前付き引数は、長い(または短い!)パラメーターリストを明確にするための(コンストラクターの場合は)クラスのプロパティを不変にすることを許可するための適切なオプション(それらをサポートする言語を想定)であり、存在を許可する要件を課すことなく不変です。部分的に構築された状態。

この種のリファクタリングを行う際に私が探すもう1つのオプションは、独立したオブジェクトとしてより適切に処理される可能性のある関連パラメーターのグループです。例として以前の回答のRectangleクラスを使用すると、x、y、高さ、および幅のパラメーターを取るコンストラクターは、xおよびyをPointオブジェクトに分解し、3つのパラメーターをRectangleのコンストラクターに渡すことができます。または、もう少し進んで2つのパラメーター(UpperLeftPoint、LowerRightPoint)にしますが、これはより根本的なリファクタリングになります。


0

それはあなたが持っている引数の種類に依存しますが、それらが多くのブール値/オプションである場合、おそらくフラグ列挙を使用できますか?


0

問題は、クラスで解決しようとしている問題の領域に深く関係していると思います。

場合によっては、7パラメーターコンストラクターが不適切なクラス階層を示している可能性があります。その場合、上で提案したヘルパー構造体/クラスが通常は適切なアプローチですが、プロパティバッグだけの構造体のロードが発生する傾向もあります。役立つことは何もしません。8つの引数を持つコンストラクターは、クラスが汎用的すぎる/多目的すぎることも示しているため、実際に役立つには多くのオプションが必要です。その場合、クラスをリファクタリングするか、実際の複雑なコンストラクターを隠す静的コンストラクターを実装できます。Shniz.NewBaz(foo、bar)は、実際に正しいパラメーターを渡して実際のコンストラクターを呼び出すことができます。


0

1つの考慮事項は、オブジェクトが作成されると、どの値が読み取り専用になるかです。

公的に書き込み可能なプロパティは、おそらく構築後に割り当てることができます。

最終的に値はどこから来るのですか?おそらく、一部の値は本当に外部のものであり、他の値は、実際にはライブラリによって維持される構成またはグローバルデータからのものです。

この場合、コンストラクターを外部使用から隠し、作成関数を提供できます。create関数は、真に外部の値を取得してオブジェクトを構築し、ライブラリにのみ利用可能なアクセサを使用して、オブジェクトの作成を完了します。

オブジェクトに完全な状態を与えるために7つ以上のパラメーターを必要とするオブジェクトがあり、それらがすべて実際に外部にあるのは非常に奇妙です。


0

clasに引数が多すぎるコンストラクタがある場合、それは通常、責任が多すぎることを示しています。おそらく、同じ機能を提供するために協力する別々のクラスに分割できます。

コンストラクターに多くの引数が本当に必要な場合は、Builderパターンが役立ちます。目標は、すべての引数をコンストラクタに渡すことです。そのため、その状態は最初から初期化され、必要に応じてクラスを不変にすることができます。

下記参照 :

public class Toto {
    private final String state0;
    private final String state1;
    private final String state2;
    private final String state3;

    public Toto(String arg0, String arg1, String arg2, String arg3) {
        this.state0 = arg0;
        this.state1 = arg1;
        this.state2 = arg2;
        this.state3 = arg3;
    }

    public static class TotoBuilder {
        private String arg0;
        private String arg1;
        private String arg2;
        private String arg3;

        public TotoBuilder addArg0(String arg) {
            this.arg0 = arg;
            return this;
        }
        public TotoBuilder addArg1(String arg) {
            this.arg1 = arg;
            return this;
        }
        public TotoBuilder addArg2(String arg) {
            this.arg2 = arg;
            return this;
        }
        public TotoBuilder addArg3(String arg) {
            this.arg3 = arg;
            return this;
        }

        public Toto newInstance() {
            // maybe add some validation ...
            return new Toto(this.arg0, this.arg1, this.arg2, this.arg3);
        }
    }

    public static void main(String[] args) {
        Toto toto = new TotoBuilder()
            .addArg0("0")
            .addArg1("1")
            .addArg2("2")
            .addArg3("3")
            .newInstance();
    }

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