Спосіб повернення декількох повернених значень методу: ввести метод всередині класу, що представляє повернене значення. Це гарний дизайн?


15

Мені потрібно повернути 2 значення з методу. Мій підхід такий:

  1. створити внутрішній клас з 2 полями, які будуть використані для збереження цих двох значень
  2. помістити метод всередині цього класу
  3. інстанціювати клас та викликати метод.

Єдине, що буде змінено в методі, це те, що врешті-решт він призначить ці 2 значення полям екземпляра. Тоді я можу звернутися до цих значень, посилаючись на поля цього об’єкта.

Це хороший дизайн і чому?


Інший варіант (ймовірно, поганий): див BitInteger[] java.math.BigInteger.divideAndRemainder(BitInteger val). Він повертає 2 цілих числа у якості повернених значень у масиві.
EarlNameless

Якого типу є два значення, які ви хочете повернути?
Tulains Córdova

Можливий дублікат - stackoverflow.com/questions/12668186/… .
m3th0dman

Відповіді:


15

Я б заперечував це наступним чином:

  • Чому саме ваш метод повертає кілька значень? Про яку згуртованість ми говоримо - чи повинні ці значення насправді бути полями для одного класу, чи вони просто випадково повертаються тим самим методом, але інакше не пов'язані між собою? Якщо це останнє, ви, можливо, захочете розглянути розділення методу на два методи. Редагувати: використовуйте судження тут; іноді тип "випадкової" згуртованості може бути найкращим варіантом. Іншим варіантом є використання парних або кортежних конструкцій, хоча в OOP вони зазвичай не спостерігаються в загальнодоступних API (деякі помітні винятки - це стандартні колекції тощо).
  • Якщо ці цінності заслуговують на формування класу, я, мабуть, радить не використовувати внутрішній клас. Внутрішні класи зазвичай використовуються як внутрішні деталі реалізації, які приховані зовні. Чи є якась причина, чому саме цей результат не повинен бути «повноцінним» класом?
  • Які операції застосовні до цього нового класу, крім зберігання даних? В об'єктно-орієнтованому дизайні ви хочете, щоб відповідна поведінка була близькою до відповідних даних (які, здається, теж ваші наміри). Чи повинен метод, який ви посилаєтесь, не жити на цьому класі?

Підводячи підсумок, я побачив би, чи зможу я перетворити цей "об'єкт даних" у розроблений клас із даними та поведінкою. В якості додаткового коментаря ви можете зробити клас незмінним, оскільки його стан встановлюється один раз. Зробити його незмінним допоможе запобігти його неправильному встановленню чи зміні пізніше (скажімо, хтось встановить одне з полів на нуль і передасть його уздовж).

Редагувати: Як правильно вказує Паткос Цсаба, принцип, який тут застосовується, - це Принцип єдиної відповідальності ( SRP ) - клас, який ви намагаєтесь створити, дійсно повинен нести одну відповідальність (визначається як причина зміни ). Це керівництво щодо проектування повинно допомогти вам зрозуміти, чи належать ваші два поля до одного класу, чи ні. Для прикладу з Вікіпедії ваш клас може розглядатися як тип звіту; в цьому випадку він відповідає SRP, але важко коментувати без додаткової інформації.


Хоча я погоджуюсь із загальною ідеєю цієї відповіді, є обґрунтовані випадки, коли дві тісно пов’язані частини даних обчислюються разом, але немає сенсу зв’язувати їх інакше ніде в програмі. У такому випадку це може бути досить чистим, щоб повернути щось подібне Pair<OneClass, AnotherClass>. Деякі люди не погоджуються . У будь-якому випадку, вона Pairповинна бути детальною інформацією про реалізацію та ніколи не з’являтися у відкритому методі API.
9000

@ 9000 я згоден; Я насправді мав на увазі, що слово вважається прийнятим буквально в цьому випадку, тобто розщеплення методу не завжди може бути найкращим рішенням, це лише груба вказівка ​​в цьому напрямку. Я зроблю редагування в цих рядках.
Даніель Б

1
Гарна відповідь. Єдине, що я хочу додати - це посилання на Принцип єдиної відповідальності (SRP) ( en.wikipedia.org/wiki/Single_responsibility_principle ). Якщо це встановлено, дуже можливо, що обговорюваний метод - це просто просте порушення SRP, а розкол - просте рішення. На мій досвід, коли метод хоче повернути 2 або більше значень, у 90% випадків там є два способи або слід витягти інший клас.
Паткос Чаба

@PatkosCsaba спасибі, зробила редагування, щоб включити його. Я, як правило, дотримуюся пояснення речей з точки зору зв'язку та згуртованості, але, мабуть, принципи SOLID розглядаються як основні правила, якими потрібно жити в наші дні.
Даніель Б

@DanielB: Я бачу SOLID як вищий рівень і, ймовірно, легше зрозуміти поняття. Зв'язок і згуртованість все ще є базовою лінією, але вони нижчого рівня. SOLID широко використовує зв'язок і згуртованість, щоб пояснити свої принципи та представити їх на більш загальному рівні.
Паткос Чаба

10

Існує концепція Tuple, яка представлена ​​іншими мовами, наприклад, 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(), щоб уникнути необхідності вказувати параметри типу в конструкторі. Крім того, я б назвав цей клас, Pairа не Tuple, враховуючи, що він може представляти лише 2-кратні значення.
серпень

5

Здається, що цей клас знімає відповідальність з іншого класу, і це змушує мене думати, що цей дизайн не чудовий.

Для методу, який повертає значення, що перемножуються, я вважаю за краще

  • повернути загальний контейнер (наприклад, Список або Карта), що містить значення, що повертаються

або

  • створити клас для повернутого значення, який містить просто необхідні поля + 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;
   }
}

Оголошення полів публічним додає можливість зміни значень окремо, хоча чітко значення мають співвідношення (інакше їх не потрібно було б повертати тим самим методом). Я б дуже відштовхував цей зразок у цій особливій ситуації. Але головне - дискусія між загальнодоступними та приватними атрибутами не має нічого спільного з питанням ОП, і я не бачу причин для останнього речення в інакшій хорошій відповіді.
шарфридж

Першому слід віддати перевагу.
Хуанін

scarfridge: Точка взята, останнє речення вилучено.
користувач281377

2
Просто використовуйте загальнодоступні фінальні поля, без причин марнувати час з аксесуарами.
аугурар

1

Введення декількох повернених значень методу в його власний клас / структуру часто використовується в системах на основі повідомлень, які мають один клас для запиту та відповіді . Прикладом цього є Простий протокол доступу до об’єктів (SOAP) .

Це хороший дизайн і чому?

Принаймні, це досить часто. Якщо це добре чи погано, залежить від вашої спеціальної скриньки.


0

Коротка відповідь: Ви можете повернути масив або Список з двома значеннями.

Я особисто написав би два чіткі методи, наприклад

int x = obj.getX();
int y = obj.getY();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.