メソッドから複数の戻り値を返す方法:戻り値を表すクラス内にメソッドを配置します。それは良いデザインですか?


15

メソッドから2つの値を返す必要があります。私のアプローチは次のとおりです。

  1. これらの2つの値を保持するために使用される2つのフィールドを持つ内部クラスを作成します
  2. そのクラス内にメソッドを配置します
  3. クラスをインスタンス化し、メソッドを呼び出します。

メソッドで変更される唯一のことは、最終的にインスタンスのフィールドにこれらの2つの値を割り当てることです。次に、そのオブジェクトのフィールドを参照することで、これらの値に対処できます。

それは良いデザインですか?それはなぜですか?


別のオプション(おそらく悪いオプション):を参照してくださいBitInteger[] java.math.BigInteger.divideAndRemainder(BitInteger val)。配列の戻り値として2つの整数を返します。
EarlNameless

返される2つの値はどのタイプですか?
Tulainsコルドバ

回答:


15

私はこれを次の行に沿って議論します:

  • メソッドが正確に複数の値を返すのはなぜですか?私たちはどのような凝集性について話しているのでしょうか?それらの値は実際には単一のクラスのフィールドなのでしょうか、それとも同じメソッドによって偶然に返されるだけなのでしょうか?後者の場合、メソッドを2つのメソッドに分割することを検討してください。編集:ここであなたの判断を使用してください。時々、「偶然の」凝集のタイプが最良の選択肢かもしれません。もう1つのオプションは、ペアまたはタプル構造を使用することです。ただし、OOPでは、これらは通常、パブリックAPIには見られません(いくつかの顕著な例外は標準コレクションなどです)。
  • 値がクラスを形成するに値する場合は、おそらく内部クラスを使用しないことをお勧めします。通常、内部クラスは内部実装の詳細として使用され、外部からは見えません。この結果がそれ自体で「本格的な」クラスにならない理由はありますか?
  • データを保持する以外に、この新しいクラスに適用できる操作は何ですか?オブジェクト指向設計では、関連する動作を関連データに近づける必要があります(これもあなたの意図のようです)。あなたが参照しているメソッドは、このクラスではなく生きるべきですか?

要約すると、この「データオブジェクト」を、データと動作の両方を備えた本格的なクラスに変えることができるかどうかがわかります。追加のコメントとして、状態が1回設定されるため、クラスを不変にすることができます。不変にすると、誤って設定されたり、後で変更されたりすることを防ぐのに役立ちます(たとえば、誰かがフィールドの1つをnullに設定して渡すなど)。

編集:Patkos Csabaが正しく指摘しているように、ここで適用されている原則は単一責任原則(SRP)です-作成しようとしているクラスには実際に1つの責任があります(変更の理由として定義)。この設計ガイドラインは、2つのフィールドが単一のクラスに属しているかどうかを判断するのに役立ちます。ウィキペディアの例に固執するには、クラスをレポートの一種と見なすことができます。この場合、SRPに準拠していますが、追加情報なしでコメントすることは困難です。


私はこの答えの一般的な考え方に同意しますが、2つの密接に関連するデータを一緒に計算する正当なケースがありますが、プログラム内の別の場所でそれらを結び付ける意味はありません。そのような場合には、のようなものを返すのに十分きれいかもしれませんPair<OneClass, AnotherClass>。一部の人々は同意しないだろう。いずれにせよ、Pair実装の詳細であり、パブリックAPIメソッドには決して表示されません。
9000

@ 9000同意します。私は実際、この場合、文字通り考慮されるという言葉を意味しました。つまり、メソッドを分割することは常に最良の解決策ではないかもしれません。これらの線に沿って編集します。
ダニエルB

1
いい答えです。追加する唯一のものは、単一責任原則(SRP)(en.wikipedia.org/wiki/Single_responsibility_principle)への参照です。チェックされている場合、議論中の方法が単にSRPの単純な違反であり、分割が単純なソリューションである可能性が非常に高くなります。私の経験では、メソッドが2つ以上の値を返したい場合は、90%のケースで2つのメソッドがあるか、別のクラスを抽出する必要があります。
パトコスチャバ

@PatkosCsabaありがと、編集して作成しました。私は通常、結合と結束の観点から物事を説明することに固執しますが、固い原則は最近まで生きるための基本的なルールと見られていると思います。
ダニエルB

@DanielB:SOLIDはより高いレベルであり、おそらく概念を理解しやすいと思います。結合と結合は依然としてベースラインですが、より低いレベルです。SOLIDは結合と結合をうまく利用して、その原理を説明し、より一般的なレベルでそれらを提示します。
パトコスチャバ

10

Pythonなどの他の言語で機能するタプルの概念があります。

簡単に再利用できるこのジェネリッククラスのインスタンスを返すことができます。

public class TypedTuple<L, R> implements Serializable {
private static final long serialVersionUID = 1L;

  protected L left;
  protected R right;

  protected TypedTuple() {
    // Default constructor for serialization
  }

  public TypedTuple(L inLeft, R inRight) {
    left = inLeft;
    right = inRight;
  }

  public L getLeft() {
    return left;
  }

  public R getRight() {
    return right;
  }
}

2
create()コンストラクターで型パラメーターを指定する必要を回避するために、一般的な静的メソッドがあると便利な場合があります。また、2タプルの値しか表すことができないPairのでTuple、このクラスの名前はでなく、このクラスにします。
8

5

このクラスは別のクラスから責任を奪っていると思われるため、このデザインは素晴らしいものではないと考えさせられます。

マルチブル値を返すメソッドの場合、私はむしろ

  • 戻り値を含む汎用コンテナー(リストやマップなど)を返します

または

  • 必要なフィールド+ getter +すべてのフィールドを持つコンストラクターのみを含む戻り値のクラスを作成します

2番目のオプションの例:

public Class FooBarRetval {
   private String foo;
   private int bar;

   public FooBarRetval (String foo, int bar) {
      this.foo = foo;
      this.bar = bar;
   }

   public String getFoo() {
      return foo;
   }

   public int getBar() {
      return bar;
   }
}

フィールドを公開すると、値を個別に変更するオプションが追加されますが、値には明らかに関係があります(そうでなければ、同じメソッドで返す必要はありません)。この特別な状況では、このパターンを非常に落胆させます。しかし、主なポイントは、パブリック属性とプライベート属性の議論はOPの質問とは関係がなく、そうでなければ良い答えの最後の文の理由はないと思います。
スカーフリッジ

最初のものが優先されるはずです。
フアン

スカーフリッジ:ポイントが取られ、最後の文が削除されました。
user281377

2
パブリックな最終フィールドを使用するだけで、アクセサと時間を無駄にする必要はありません。
8


0

短い答え:2つの値を持つ配列またはリストを返すことができます。

私は個人的に、次のような2つの異なるメソッドを記述します。

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