一种从方法返回多个返回值的方法:将方法放入表示返回值的类中。这是一个好的设计吗?


15

我需要从一个方法返回2个值。我的方法如下:

  1. 创建一个具有2个字段的内部类,这些字段将用于保留这2个值
  2. 将方法放在该类中
  3. 实例化该类并调用该方法。

该方法中唯一要更改的是,最后它将为实例的字段分配这两个值。然后,我可以通过引用该对象的字段来解决这些值。

这是一个好的设计,为什么?


另一种选择(可能是一个不好的选择):请参见BitInteger[] java.math.BigInteger.divideAndRemainder(BitInteger val)。它在数组中返回2个整数作为其返回值。
EarlNameless 2012年

您要返回的两个值是什么类型?
图兰斯·科尔多瓦

Answers:


15

我将按照以下思路对此进行争论:

  • 为什么您的方法确切返回多个值?我们在说什么样的内聚性-这些值实际上应该是单个类上的字段,还是由相同的方法巧合地返回,而在其他方面却不相关?如果是后者,则可能需要考虑将方法分为两个方法。编辑:在这里使用您的判断;有时,“巧合”的内聚性可能是最好的选择。另一个选择是使用对或元组构造,尽管在OOP中,通常在公共API中看不到它们(某些值得注意的例外是标准集合等)。
  • 如果这些值确实值得组成一个类,那么我建议不要使用内部类。内部类通常用作内部实现细节,对外部而言是隐藏的。有什么原因使该结果本身不应该成为“成熟的”类吗?
  • 除了保存数据,哪些操作适用于此新类?在面向对象设计中,您希望使相关行为接近相关数据(这似乎也是您的意图)。您所引用的方法是否应该不属于此类?

总而言之,我将查看是否可以将“数据对象”转换为既具有数据又具有行为的成熟类。作为附加说明,您可能希望使该类不可变,因为它的状态仅被设置一次。将其设置为不可变将有助于防止对其进行错误设置或以后修改(例如,有人将其中一个字段设置为null并将其传递)。

编辑:正如Patkos Csaba正确指出的那样,此处应用的原则是单一职责原则(SRP)-您尝试创建的类确实应该承担一项责任(定义为更改原因)。此设计指南应帮助您确定两个字段是否属于一个类。坚持以Wikipedia为例,您的课程可以看作是一种报告,在这种情况下,它符合SRP,但是如果没有更多信息,则很难进行注释。


虽然我同意此答案的一般思想,但在合理的情况下,将两个紧密相关的数据计算在一起,但是在程序中的其他任何地方将它们捆绑在一起是没有意义的。在这种情况下,它可能足够干净以返回类似的内容Pair<OneClass, AnotherClass>。有些人会不同意。无论如何,Pair都应该是实现细节,并且永远不要出现在公共API方法中。
9000

@ 9000我同意;我其实是这个词考虑要在这种情况下,从字面上理解,即分裂法可能并不总是最佳的解决方案,它只是在这个方向的粗略指示。我将按照这些内容进行编辑。
Daniel B

1
好答案。我唯一要添加的是对单一职责原则(SRP)的引用(en.wikipedia.org/wiki/Single_responsibility_principle)。如果选中,则所讨论的方法很可能仅是违反SRP的一种简单方法,而拆分是一种简单的解决方案。以我的经验,每当一个方法要返回2个或多个值时,在90%的情况下,那里有2个方法或应提取另一个类。
Patkos Csaba

@PatkosCsaba谢谢,进行了编辑以包括其中。我通常坚持用耦合和内聚来解释事物,但是我认为SOLID原则已被视为当今生活的基本规则。
Daniel B

@DanielB:我认为SOLID是更高级别的,并且可能更容易理解概念。耦合和内聚仍然是基线,但是它们的水平更低。SOLID充分利用了耦合和内聚来解释其原理并在更通用的层次上进行介绍。
Patkos Csaba

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
有时最好有一个通用的static方法create(),以避免必须在构造函数中指定类型参数。另外,我将命名该类Pair而不是Tuple,因为它只能表示2个元组的值。
augurar 2014年

5

看来这堂课代替了另一堂课,这让我觉得这种设计不是很好。

对于返回多重值的方法,我宁愿

  • 返回包含返回值的通用容器(例如List或Map)

要么

  • 为返回值创建一个类,该类仅包含必需的字段+ getters +带有所有字段的构造函数

第二个选项的示例:

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的问题无关,我认为没有其他理由可以在最后一个句子中得到一个好的答案。
Scarridge

第一个应该是首选。
胡安2012年

围巾岭:点,最后一句删除。
user281377

2
只需使用公共的final字段,没有理由浪费时间与访问器。
augurar 2014年


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.