Используя перечисления или набор классов, когда я знаю, что у меня есть конечный набор различных опций? - PullRequest
4 голосов
/ 08 апреля 2010

Допустим, я определил следующий класс:

public abstract class Event {
    public DateTime Time { get; protected set; }

    protected Event(DateTime time) {
        Time = time;
    }
}

Что бы вы предпочли между этим:

public class AsleepEvent : Event {
    public AsleepEvent(DateTime time) : base(time) { }
}

public class AwakeEvent : Event {
    public AwakeEvent(DateTime time) : base(time) { }
}

и это:

public enum StateEventType {
    NowAwake,
    NowAsleep
}    

public class StateEvent : Event {
    protected StateEventType stateType;

    public StateEvent(DateTime time, StateEventType stateType) : base(time) {
        stateType = stateType;
    }
}

а почему? Я обычно более склонен к первому варианту, но не могу объяснить почему. Это совершенно то же самое или есть какие-то преимущества в использовании одного вместо другого? Возможно, с помощью первого метода проще добавить больше «состояний», хотя в этом случае я на 100% уверен, что мне понадобятся только два состояния: теперь бодрствующий и теперь спящий (они сигнализируют моменты, когда один просыпается, а другой засыпает).

Ответы [ 5 ]

6 голосов
/ 08 апреля 2010

Я предпочитаю первое. Вы можете прикрепить методы и поведение к классам и отойти от шаблона switch / case, общего с enums, к истинному полиморфизму (и его преимуществам в отношении обслуживания - добавления новых падежей и т.

3 голосов
/ 08 апреля 2010

Настоящие ООПеры не используют if! Предпочитаю полиморфизм условным.

Конечно, могут быть ситуации, когда enum - это путь (скажем, если у вас очень, очень большое количество состояний или вы знаете, что для домена, очень вероятно, что все наблюдатели будут заинтересованы во всех переходах), но в общем случае первый вариант менее сложен. Используя второй подход, каждый слушатель должен повторить один и тот же кусок кода:

if (theStateImInterestedIn == event.stateType){ 
    /* actual code */ 
}

И каждый слушатель нуждается в этом, за исключением слушателей, которые одинаково реагируют на все переходы! Дублирование кода! Aaaaargh! Как мы все знаем, повторяющийся код вызывает ошибки (отсюда и принцип DRY ), и поэтому мы можем заключить, что ваше внутреннее чувство правильное - первый вариант (с использованием двух разных классов) лучше, так как каждый человек реализация слушателя будет иметь меньше котла.

Также; добавьте туда else, и у вас появятся интересные времена, когда вы добавите новое состояние: некоторые слушатели интересовались обоими типами событий и поэтому предположили, что ветвь else означает «состояние, которое я не сделал» t проверить в if ". Теперь они ломаются, потому что предложение else охватывает> 1 состояние.

2 голосов
/ 08 апреля 2010

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

2 голосов
/ 08 апреля 2010

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

1 голос
/ 08 апреля 2010

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

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

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