Должен ли я переименовать возвращаемый тип во что-то более общее, чтобы использовать его повторно? - PullRequest
2 голосов
/ 25 февраля 2010

Так что я допустил ошибку.

При первоначальном написании подписи для API я создал что-то вроде этого:

public JellyBeanResult getJellyBeanReport();

Теперь получается, что я хотел бы повторно использовать более конкретный объект JellyBeanResult из-за его функциональности, но было бы странно, если бы другие функции возвращали тип, названный для другого процесса. Есть несколько способов исправить это, что я могу придумать. Я мог бы переименовать тип возвращаемого значения во что-то более общее:

public GenericResult getJellyBeanReport();
public GenericResult getChocolateBarReport();

но это сломало бы любой код, который использует API. Я мог бы создать новый, более точно названный класс, который расширяет SpecificResult, который более точно соответствует новой функции:

public class ChocolateBarResult extends JellyBeanResult{};

public JellyBeanResult getJellyBeanReport();
public ChocolateBarResult getChocolateBarReport();

Но это действительно, действительно ужасно, и проблема все еще остается, если я хочу снова использовать тип возврата в будущем. Как я могу очистить эти подписи, чтобы сделать их менее запутанными, не нарушая код, который их использует?

Ответы [ 7 ]

6 голосов
/ 25 февраля 2010

Переместите основную функциональность с JellyBeanResult на GenericResult, и JellyBeanResult расширяет GenericResult:

public class JellyBeanResult extends GenericResult {}

public JellyBeanResult getJellyBeanReport();
public GenericResult getChocolateBarReport();

или если вы хотите быть полностью последовательным:

public class JellyBeanResult extends GenericResult {}
public class ChocolateBarResult extends GenericResult {}

public JellyBeanResult getJellyBeanReport();
public ChocolateBarResult getChocolateBarReport();
4 голосов
/ 25 февраля 2010

Вы правы, иметь ChocolateBarResult extension JellyBeanResult было бы плохо, потому что JellyBeanResult, вероятно, имеет методы и поля (например, "color" для желейных бобов), которые не имеют смысла для плитки шоколада. , Так что не делай этого. : -)

А как насчет создания новых методов для возврата правильного типа результата (GenericResult), а затем маркирования узкого getJellyBeanReport() метода как @Deprecated, чтобы отговорить любого новичка от его использования?

4 голосов
/ 25 февраля 2010

Специфика любого API ' true ' заключается в том, что его невозможно изменить. Вы не можете просто изменить / удалить существующие методы. Вы можете только добавить новую функциональность.

Единственный способ увидеть, что вы должны создать правильный набор методов (как в вашем примере с GenericReport) и пометить старые методы с пометкой @Deprecated.

0 голосов
/ 26 февраля 2010

Если вы все равно собираетесь провести рефакторинг, имеет смысл подумать о том, чтобы сделать JellyBeanResult интерфейсом, расширяющим желаемый интерфейс GenericResult.(По сути, это интерфейс маркера для сохранения вашего предыдущего возвращаемого типа.) Ваш существующий класс JellyBeanResult становится вашей первой итерацией.заменить его с гораздо меньшим риском.

0 голосов
/ 25 февраля 2010

Возможности:

  • Если вы просто хотите повторно использовать эту функциональность, все другие классы, такие как ChocolateBarResult, могут использовать JellyBeanResult вместо его расширения. Помните, что состав часто лучше наследования.
  • Сохраняйте выпуск текущей версии API, чтобы существующие пользователи были в порядке. Создайте новую версию, в которую будут внесены ваши изменения, так что, если пользователям нужны новые функции, им необходимо обновить свою кодовую базу. Если вы сделаете это, создайте какое-то руководство по изменениям и, возможно, осудите метод для цикла выпуска или двух, чтобы разрешить изменение.
  • Планируйте API лучше. Dogfood ваш код. Старайтесь не выпускать его как API, пока у вас не будет хорошего (разнообразного) набора пользователей.
0 голосов
/ 25 февраля 2010

Я точно не знаю, для чего ты идешь, но может быть что-то вроде этого?

public JellyBeanResult getJellyBeanReport() {
    return getJellyBeanReport(JellyBeanResult.class);
}

public <T extends JellBeanResult> getJellyBeanReport(Class<T> resultType) {
    // get the correct report type
}
0 голосов
/ 25 февраля 2010

Предполагая, что вы не выпустили текущую версию API, можете ли вы изменить рефакторинг для использования универсального интерфейса и ковариантных типов возврата?

public interface ConfectionaryResult {...}
public class ChocolateBarResult implements ConfectionaryResult {...}
public class JellyBeanResult implements ConfectionaryResult {...}

public interface ConfectionaryInventory {
    ConfectionaryResult getReport();
}

public class JellyBeanInventory implements ConfectionaryInventory {
    JellyBeanResult getReport() {...}

    @deprecated "Use JellyBeanInventory.getReport() instead"
    JellyBeanResult getJellyBeanReport() {
        return getReport();
    }
}

public class ChocolateBarInventory implements ConfectionaryInventory {
    ChocolateBarResult getReport() {...}
}

Я предполагаю, что оригинальные методы жили внутри класса инвентаря - что может быть и не так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...