Статический метод создания - плюсы и минусы по сравнению с конструкторами


11

Каковы плюсы и минусы использования статических методов создания объектов над конструкторами?

class Foo {
  private Foo(object arg) { }

  public static Foo Create(object arg) {
    if (!ValidateParam(arg)) { return null; }
    return new Foo(arg);
  }
}

Мало, что я могу думать о:

Плюсы:

  • Возврат null вместо выдачи исключения (назовите его TryCreate). Это может сделать код более лаконичным и чистым на стороне клиента. Клиенты редко ожидают, что конструктор потерпит неудачу.
  • Создавать различные виды объектов с четкой семантикой, например, CreatFromName(String name)иCreateFromCsvLine(String csvLine)
  • При необходимости может вернуть кешированный объект или производную реализацию.

Минусы:

  • Менее обнаруживаемый, более сложный для просмотра кода.
  • Некоторые шаблоны, такие как сериализация или рефлексия, являются более сложными (например Activator<Foo>.CreateInstance())

1
Это медленнее. Вы должны обработать нулевую ссылку в любом случае.
Амир Резаи

1
@Amir Обработка null is ( Foo x = Foo.TryCreate(); if (x == null) { ... }). Обработка исключения ctor - это ( Foo x; try { x = new Foo(); } catch (SomeException e) { ... }). При вызове обычного метода я предпочитаю исключения кодам ошибок, но с созданием объекта, TryCreateкажется, чище.
ДБКК

Сделаете ли вы в своей проверке проверку типа?
Амир Резаи

Что касается второго Pro, «Создавайте различные виды объектов с четкой семантикой, например, CreatFromName (String name) и CreateFromCsvLine (String csvLine)», вам может быть лучше создавать Nameи печатать CsvLine, а не выражать требования через имена методов. Это позволит вам перегрузить Create. Использование строк для обоих можно рассматривать как «примитивную одержимость» (если вы не сделали этот выбор по известным причинам производительности). Проверьте Object Calisthenics для забавного способа исследовать это.
Бентайлорук

Ответы:


7

Самый большой недостаток статических « создателей » - это, вероятно, ограничение наследования. Если вы или пользователь вашей библиотеки наследует класс от вашего Foo, то Foo::Create()становится практически бесполезным. Вся определенная логика должна быть переписана заново в унаследованном Create().

Я бы предложил компромисс: определите конструктор с тривиальной логикой инициализации объекта, который никогда не завершится с ошибкой / броском, затем определите создателя (ей) с помощью кэширования, альтернативной конструкции и т. Д. Это оставляет возможность получения, и вы получаете выгоду от наличия создателей для данного класса ,


1
На практике это не проблема, потому что большинство классов не предназначены для наследования (и, следовательно, должны быть запечатаны / окончательны). Если позже окажется, что вы хотите открыть класс до наследования, вы всегда можете переместить любую логику инициализации в защищенный конструктор.
Довал

7

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.