Какой лучший способ вернуть несколько значений enum? (Java и C #) - PullRequest
0 голосов
/ 18 ноября 2009

больше исходного содержимого удалено, чтобы сделать вопрос более легким для ссылки:

Итак, у меня есть класс House, у которого есть метод House.buy(Person p), заставляющий человека купить дом. Я хочу знать, возможно ли для Человека купить Дом, поэтому у меня также есть метод House.tryBuy(Player p), который возвращает, если Человек может купить дом. У меня есть enum BuyState со значениями вроде OK, NotEnoughMoney и AlreadyOwned. Есть несколько различных условий, которые должны быть выполнены, и клиент хотел бы знать, какие из них не удалось. Но что, если несколько условий не выполняются? У меня может быть иерархия, например, если Хаус уже принадлежит, а у Человека недостаточно денег, верните BuyStates.AlreadyOwned. Но это только позволяет мне сказать клиенту одну вещь.

Я мог бы иметь N отдельных условий и перечисление со значениями N * N, например ConditionA_AND_ConditionB_ANDConditionC, но это не имеет никакого смысла по нескольким причинам. Я знаю, что есть битовые поля с битами для каждого условия, но они кажутся слишком низкоуровневыми, раздражающими для реализации и не масштабируемыми. Так что мне нужен способ вернуть список значений из перечисления, так как насчет класса, подобного этому:

class C<type_of_enum> {
    private List<type_of_enum> values;

    //etc etc
}

Это «лучший» дизайн?

(оставить этот вопрос о Java и C #, чтобы ответы оставались действительными)

Ответы [ 8 ]

12 голосов
/ 18 ноября 2009

В Java наиболее естественный способ сделать это с помощью EnumSet. Пример построения:

return EnumSet.of(BuyConditions.NotEnoughMoney, BuyConditions.AlreadyOwned);
8 голосов
/ 18 ноября 2009

В C # я бы пошел для перечисления флагов.

Проверка Проектирование перечисления флагов .

7 голосов
/ 18 ноября 2009

Это «лучший» дизайн?

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

Во-первых, дом - это не то, что покупает человек. Человек - это то, что покупает дом. Метод «купить» должен быть «лицом», а не «домом».

Во-вторых, дом - это не то, что определяет, можно ли купить дом. владелец дома - это лицо, которое определяет, можно ли его купить. (Почему возникает ошибка «уже принадлежит»? Конечно, дом уже принадлежит. Кто-то владеет им.)

В-третьих, вам, возможно, придется подумать о том, что происходит в мире, где несколько покупателей могут пытаться купить дом одновременно. На самом деле продавец собирает различные предложения и делает встречные предложения, продажи могут зависеть от других событий и так далее. Должны ли все эти вещи присутствовать в модели? Если да, то где? Вероятно, в состоянии объекта, представляющего владельца, так как с владельцем является предметом, о котором договариваются.

В-четвертых, в действительности в сделках по покупке жилья обычно участвуют доверенные третьи стороны для условного депонирования, а также различные другие стороны, такие как кредиторы продавца и покупателя, которые могут предоставлять средства или держать залоговое удержание. Отражены ли эти партии в этой модели?

В-пятых, если вы намерены добавить к своей модели «причины, по которым вы не можете купить этот дом», тогда вы описываете систему политики . В этом случае представьте политики как первоклассные объекты в вашей системе, чтобы ими можно было манипулировать, как и любыми другими объектами. Владельцы имеют политику о том, на каких условиях они будут продавать. У банков есть политика относительно условий, при которых они будут кредитовать. И так далее.

В этой модели ваша проблема становится «спросить механизм разрешения политики, если покупатель соблюдает все необходимые условия, наложенные деревьями политики каждого соответствующего агентства для покупки данного дома». Другими словами, вопрос "может ли X купить Y?" не для X или Y, чтобы выяснить; дело в том, что механизм разрешения политики должен сработать, и именно это возвращает вам список политик, которые X не смог выполнить, чтобы купить Y у Z.

Имеет смысл?

1 голос
/ 18 ноября 2009

Я думаю, что возвращение списка причин не покупать - это здорово; это очень выразительно из того, что вы пытаетесь сделать. Набор, вероятно, будет более уместным, но лишь немного.

1 голос
/ 18 ноября 2009

Да, это похоже на лучший дизайн. Вы хотите вернуть список (или набор) причин, поэтому естественно вернуть его в виде набора.

0 голосов
/ 18 ноября 2009

Вместо того, чтобы возвращать список, вы можете передать указатель списка на функцию, которая будет заполнена причинами в случае возникновения ошибок. Сама функция может возвращать 0 для обозначения успеха и 1 для неудачи, в этом случае вы можете проверить содержимое списка.

Это позволит быстрее узнать, был ли вызов функции успешным или нет, при условии, что большую часть времени он будет успешным.

0 голосов
/ 18 ноября 2009

Вы можете использовать обратный вызов:

class House {

    public void buy(Result result) {

        if (true)
            result.ok(this);
        else
            result.error(this, EnumSet.of(Status.NOT_ENOUGH_MONEY, Status.ALREADY_OWNED));

    }

}

enum Status {

    NOT_ENOUGH_MONEY,
    ALREADY_OWNED

}

interface Result {

    public void ok(House house);

    public void error(House house, EnumSet<Status> status);

}
0 голосов
/ 18 ноября 2009

Звучит хорошо для меня. Вы хотите вернуть список условий, которые не удалось, и вы возвращаете список условий, которые не удалось.

...