В языке, где доступны и то, и другое, вы бы предпочли видеть конструктор экземпляра или статический метод, который возвращает экземпляр?
Например, если вы создаете 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 от создания Bar, но он говорит мне, что мне нужно посмотреть.
Foo.New() в качестве замены по умолчанию для new и Foo.FromAbc() и т. д. для особых.
- person Pacerier; 25.06.2014
Недавно я работал над общедоступным API и мучился выбором статических фабричных методов по сравнению с конструктором. Статические фабричные методы определенно имеют смысл в некоторых случаях, но в других это не так ясно, и я не уверен, является ли согласованность с остальной частью API достаточной причиной для включения их вместо конструкторов.
Так или иначе, я наткнулся на цитату из интервью Билла-Веннера с Джошем Блохом, которую я нашел полезный:
Когда вы пишете класс, вы можете просмотреть приведенный в моей книге список преимуществ статических фабрик по сравнению с общедоступными конструкторами. Если вы обнаружите, что значительное количество этих преимуществ действительно применимо в вашем случае, вам следует использовать статические фабрики. В противном случае вы должны пойти с конструкторами.
Некоторые люди были разочарованы, найдя этот совет в моей книге. Они прочитали его и сказали: «Вы так сильно настаивали на общедоступных статических фабриках, что мы должны просто использовать их по умолчанию». Я думаю, что единственным реальным недостатком этого является то, что это немного смущает людей, которые привыкли использовать конструкторы для создания своих объектов. И я полагаю, что это дает немного меньше визуальной подсказки в программе. (Вы не видите нового ключевого слова.) Также немного сложнее найти статические фабрики в документации, потому что Javadoc группирует все конструкторы вместе. Но я бы сказал, что все должны постоянно учитывать статические фабрики и использовать их, когда это уместно.
Прочитав эту цитату и исследование, о котором упоминал Ури*, я Я склонен ошибаться в пользу конструкторов, если нет веских причин поступать иначе. Я думаю, что статический фабричный метод без уважительной причины, вероятно, просто ненужная сложность и чрезмерная инженерия. Хотя, возможно, завтра я снова передумаю...
*К сожалению, это исследование было сосредоточено не столько на статических фабричных методах, сколько на фабричном шаблоне (где существует отдельный фабричный объект для создания новых экземпляров), поэтому я не уверен, что можно действительно сделать вывод, что статические фабричные методы смущают многих программистов. Хотя исследование действительно произвело на меня впечатление, что они часто будут.
Если ваш объект неизменяем, вы можете использовать статический метод для возврата кэшированных объектов и сэкономить на выделении и обработке памяти.
На ICSE'07 есть документ, в котором изучалось удобство использования конструкторов и фабричных шаблонов. Хотя я предпочитаю фабричные шаблоны, исследование показало, что разработчики медленнее находили правильный фабричный метод.
http://www.cs.cmu.edu/~NatProg/papers/Ellis2007FactoryUsability.pdf
new в обычных конструкторах.
- person Pacerier; 25.06.2014
Статический метод. Затем вы можете вернуть ноль, а не генерировать исключение (если только это не ссылочный тип)
Я предпочитаю конструктор экземпляров просто потому, что это имеет для меня больше смысла, и меньше потенциальной двусмысленности с тем, что вы пытаетесь выразить (например: что, если FromCharacters - это метод, который принимает один символ). Хотя конечно субъективно.
Я лично предпочитаю видеть обычный конструктор, так как конструкторы должны использоваться для построения. Однако, если есть веская причина не его использовать, например, если FromCharacters явно заявил, что он не выделял новую память, это было бы целесообразно. «Новое» в призыве имеет значение.
По-разному. Для языков, в которых использование конструктора экземпляра является «нормальным», я обычно использовал бы его, если бы у меня не было веских причин не делать этого. Это следует принципу наименьшего удивления.
Кстати, вы забыли еще один распространенный случай: конструктор null/по умолчанию в паре с методом инициализации.
Как перефразировал Джон Скит Джоша Блоха, существует ряд причин, по которым статический фабричный метод во многих случаях предпочтительнее конструктора. Я бы сказал, что если класс простой, без дорогостоящей настройки или сложного использования, оставайтесь с идиоматическим конструктором. Современные JVM делают создание объектов чрезвычайно быстрым и дешевым. Если класс может быть подклассом или вы можете сделать его неизменяемым (большое преимущество для параллельного программирования, значение которого только возрастает), используйте фабричный метод.
Еще один совет. Не называйте фабричный метод Foo.new* или Foo.create*. Метод с такими именами всегда должен возвращать новый экземпляр, и при этом упускается одно из больших преимуществ фабричного метода. Лучшее соглашение об именах — Foo.of* или Foo.for*. библиотека Google Guava (ранее Библиотека коллекций Google) отлично справляется с это, имхо.
of* и for* лучше, чем new* или create*? Для меня важно правильно называть вещи, поэтому я хотел бы узнать здесь что-то новое.
- person stakx - no longer contributing; 09.05.2013
Конечно, у статических фабричных методов есть несколько преимуществ перед конструкторами.
getInstance() в синглтоне.