Можно ли, чтобы фабричный метод возвращал значение null?

Меня интересует лучшая практика здесь. Является ли хорошей практикой, чтобы фабричный метод возвращал значение null, если он не может ничего создать? Вот пример:

ICommand command = CommandFactory.CreateCommand(args);
if (command != null)
    command.Execute();
else
    // do something else if there is no command

Я думаю, альтернативой было бы вернуть NullCommand или что-то в этом роде, но как лучше всего?


person Jeff Pratt    schedule 20.06.2012    source источник


Ответы (4)


Я думаю, что фабричный метод потенциально может возвращать значение null в некоторых ситуациях, но нет, если это метод с именем CreateCommand. Если бы это было GetCommand или FetchCommand, все было бы в порядке... но я бы посоветовал методу Create генерировать исключение при сбое.

Хотите ли вы действительно вернуть null в этой ситуации, конечно, зависит от общей картины. (Есть ли разумная реализация нулевого объекта, которую вы могли бы вместо этого вернуть, например?)

person Jon Skeet    schedule 20.06.2012
comment
Согласен с @Jon Skeet. Create подразумевает конструктор, и вы не ожидаете null от одного из них, поэтому маловероятно, что вы будете проверять, так ли это было. - person Tony Hopkinson; 20.06.2012
comment
@TonyHopkinson: С другой стороны, вы также не ожидаете исключения от конструктора. - person Tim Schmelter; 20.06.2012
comment
@TimSchmelter: Почему бы и нет? Я бы абсолютно ожидал исключения от конструкторов в определенных ситуациях - FileStream является классическим примером... или что-либо с параметрами, которые могут быть недействительными в любой форме, например. предоставление нулевой ссылки на что-то, ожидающее ненулевой ссылки. - person Jon Skeet; 20.06.2012
comment
@JonSkeet: Да, в определенных ситуациях, но это беглый отрывок (какой правильный английский термин?). Это один из случаев, когда мне не хватает ключевого слова java throws, чтобы убедиться, что оно обрабатывается вызывающим абонентом. - person Tim Schmelter; 20.06.2012
comment
@TimSchmelter: Даже в Java вы бы не использовали его для таких вещей, как явно недопустимые параметры. По сути, я не считаю, что конструктор, вызывающий исключение, сильно отличается от метода, вызывающего исключение, за исключением того, что вам нужно быть более осторожным, если вы выделили какие-либо неуправляемые ресурсы (поскольку вызывающая сторона не сможет избавиться от вновь построенный объект). - person Jon Skeet; 20.06.2012
comment
@TimSchmelter Это должно быть редко, и я бы постарался избежать этого, например. Инициализируйте метод для ресурсов, но создание исключения намного лучше, чем альтернативы. - person Tony Hopkinson; 21.06.2012

Я согласен с Джоном Скит. CreateCommand явно подразумевает строительство.

Если вы не будете выбрасывать Exception, то в этом сценарии я бы лично выбрал реализацию NullCommand, чтобы избежать условных операторов во всех потребителях и возможных ошибок NullReferenceException.

person Pablo Romeo    schedule 20.06.2012

Возврат null в этом случае затруднит использование вашего метода; клиенты должны знать о неявном состоянии отказа. Вместо этого создайте исключение, и вы также можете предоставить клиентам отдельный метод для проверки этого условия:

if (CommandFactory.CanCreate(args)) {
  ICommand command = CommandFactory.Create(args);
  command.Execute();
}

Или сделайте фабрику инстанцируемой; что было бы лучше, если вам нужно предварительно обработать args:

CommandFactory factory = new CommandFactory(args);
if (factory.IsValid()) {
  ICommand command = factory.Create();
  command.Execute();
}

Интерфейс фабрики теперь четко и ясно дает понять, что создание может завершиться неудачей, но по-прежнему требует, чтобы клиент использовал метод проверки. Другой вариант:

ICommand command;
if (CommandFactory.TryCreate(args, out command)) {
  // creation succeeded ...
}
person Jordão    schedule 20.06.2012
comment
возможна ошибка, если они не проверяют значение null Поскольку C# не поддерживает проверенные исключения (в отличие от java), клиенты также могут выйти из строя, если не обработают это исключение, так что это не является сильным аргументом( по моему мнению). - person Tim Schmelter; 20.06.2012
comment
@TimSchmelter: я пересмотрел свою формулировку этой фразы... Надеюсь, теперь моя точка зрения стала более ясной. - person Jordão; 20.06.2012

Возвращать Null имеет смысл только в том случае, если есть причина, по которой вы хотите, чтобы пользователь проверял значение null каждый раз, когда он вызывает Create. Обычно вы считаете следующий вполне допустимым шаблоном использования:

var obj = MyFactory.CreateThing();
obj.DoSomething();

Но вы предлагаете принудительно использовать следующий шаблон использования:

var obj = MyFactory.CreateThing();
if (obj == Null) {
    // Handle null condition
} else {
    obj.DoSomething();
}

Обычно сценарий Null означает какой-то сбой, и в этом случае Exception, вероятно, имеет смысл. Но, в конечном счете, вы являетесь создателем музыки и должны решить, что разумно в мире, который вы создаете.

person tylerl    schedule 20.06.2012