На языке, где оба доступны, вы предпочитаете видеть конструктор экземпляра или статический метод, который возвращает экземпляр?
Например, если вы создаете String
из char[]
:
-
String.FromCharacters(chars);
-
new String(chars);
На языке, где оба доступны, вы предпочитаете видеть конструктор экземпляра или статический метод, который возвращает экземпляр?
Например, если вы создаете String
из char[]
:
String.FromCharacters(chars);
new String(chars);
В Effective Java, 2-е издание, Джошуа Блох, безусловно, рекомендует первое. Есть несколько причин, которые я могу вспомнить, и, несомненно, некоторые, которые я не могу:
Недостатки:
Я пишу конструктор при создании экземпляра без побочных эффектов, т.е. когда единственное, что делает конструктор, это инициализация свойств. Я пишу статический метод (и делаю конструктор закрытым), если создание экземпляра делает то, чего вы обычно не ожидаете от конструктора.
Например:
public class Foo
{
private Foo() { }
private static List<Foo> FooList = new List<Foo>();
public static Foo CreateFoo()
{
Foo f = new Foo();
FooList.Add(f);
return f;
}
}
Поскольку я придерживаюсь этого соглашения, если я вижу
Foo f = Foo.CreateFoo();
Bar b = new Bar();
во время чтения моего кода у меня есть совсем другой набор ожиданий о том, что делает каждая из этих двух строк. Этот код не говорит мне, что именно делает создание Foo отличным от создания бара, но он говорит мне, что мне нужно посмотреть.
Если ваш объект неизменен, вы можете использовать статический метод для возврата кешированных объектов и сэкономить выделение и обработку памяти.
Недавно я работал над публичным API, и я мучился от выбора статических методов factory и конструктора. Статические методы factory определенно имеют смысл в некоторых случаях, но в других случаях это не так понятно, и я не уверен, что согласованность с остальной частью API является достаточной причиной для включения их в конструкторы.
В любом случае, я наткнулся на цитату из интервью Билла-Веннерса с Джошем Блохом, которое я нашел полезным:
Когда вы пишете класс, вы можете запустите мой список книг преимущества статических заводов над общественных конструкторов. Если вы обнаружите, что значительное число таких преимущества в случае, вы должны пойти с статических фабрик. В противном случае вы должны перейдите к конструкторам.
Некоторые люди были разочарованы тем, что нашли этот совет в моей книге. Они это прочитали и сказал: "Вы так сильно спорили для общественных статических заводов, которые мы должен использовать их по умолчанию". я Единственный реальный недостаток в это значит, что это немного смущать людей, которые используются к использованию конструкторов для создания своих объекты. И я полагаю, это обеспечивает немного меньше визуальной подсказки в программа. (Вы не видите новых ключевое слово.) И это немного больше трудно найти статические фабрики в документации, поскольку Javadoc группирует все конструкторы вместе. Но я бы сказал, что каждый должен рассмотрите статические заводы времени и использовать их, когда они необходимо.
Прочитав эту цитату и исследование, о котором упомянул Ури *, я склонен ошибаться в пользу конструкторов, если нет убедительных причины делать иначе. Я думаю, что статический метод factory без уважительной причины, вероятно, просто лишняя сложность и чрезмерная инженерия. Хотя я мог бы снова передумать завтра...
* К сожалению, это исследование меньше фокусировалось на статических factory методах и более на шаблоне factory (где существует отдельный объект factory для создания новых экземпляров), поэтому я не уверен, что действительно можно сделать вывод что статические методы factory путают многих программистов. Хотя исследование дало мне впечатление, что они часто будут.
Там была статья от ICSE'07, в которой изучалась удобство использования конструкторов против шаблонов factory. Хотя я предпочитаю шаблоны factory, исследование показало, что разработчики медленнее находили правильный метод factory.
http://www.cs.cmu.edu/~NatProg/papers/Ellis2007FactoryUsability.pdf
Статический метод. Затем вы можете вернуть null, а не бросать исключение (кроме ссылочного типа)
Я предпочитаю конструктор экземпляров только потому, что это имеет для меня больше смысла, и там меньше потенциальной двусмысленности с тем, что вы пытаетесь выразить (например: что, если FromCharacters - это метод, который принимает один символ). Конечно, субъективно.
Я лично предпочитаю видеть обычный конструктор, так как конструкторы должны использоваться для построения. Однако, если есть веские причины не использовать его, то есть если FromCharacters явно заявили, что он не выделяет новую память, это было бы полезно. "Новый" в вызове имеет смысл.
Это зависит. Для языков, в которых использование конструктора экземпляра является "нормальным", я обычно использовал бы его, если бы у меня не было серьезных оснований. Это следует принципу наименьшего удивления.
Кстати, вы забыли другой общий случай: конструктор null/default в паре с методом инициализации.
Как перефразировал Джон Скит Джош Блох, существует ряд причин, по которым метод статической фабрики предпочтительнее конструктора во многих случаях. Я бы сказал, что если класс простой, без дорогой установки или сложного использования, оставайтесь с идиоматическим конструктором. Современные JVM делают создание объектов чрезвычайно быстрым и дешевым. Если класс может быть разделен на подклассы или вы можете сделать его неизменным (большое преимущество для параллельного программирования, которое только станет более важным), то используйте метод фабрики.
Еще один совет. Не Foo.new*
фабричный метод Foo.new*
или Foo.create*
. Метод с этими именами должен всегда возвращать новый экземпляр, и при этом упускается одно из больших преимуществ фабричного метода. Лучшее соглашение об именах - Foo.of*
или Foo.for*
. Библиотека Google Guava (ранее Библиотека коллекций Google) отлично справляется с этой задачей, imho.
Конечно, есть несколько преимуществ статических фабричных методов перед конструкторами.
getInstance()
в синглтоне.