Использовать свойство как фабричный метод

У меня есть базовый класс Base, которому нужно создавать экземпляры другого типа TRequired, однако только производные классы от Base знают, как их создавать.

Плохо ли использовать абстрактное свойство в качестве фабричного метода? например

protected abstract TRequired NewTRequired { get; }

Должен ли я использовать метод по какой-то причине? Есть ли руководство, почему я должен/не должен использовать свойство здесь?


person D.R.    schedule 15.07.2013    source источник


Ответы (3)


Вы должны определенно использовать метод, потому что доступ к этому элементу делает что-то. Вызов метода — хороший способ позволить коду говорить самому за себя в этом отношении.

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

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

var prototype = Factory.NewTRequired;

Я намеренно поместил результат в переменную с именем prototype, чтобы лучше показать, что даже информированный читатель этого кода может быть легко сбит с толку: было бы разумно увидеть это и подумать «верно, значит, NewTRequired является прототипом объекта для ИКС". Этот читатель наверняка был бы поражен результатом кода, подобного этому:

var eq = object.ReferenceEquals(prototype, Factory.NewTRequired);

Сравните это с фабричным методом. Теперь этот код может издавать легкий запах:

// hmmm... are we actually using this as a prototype?
// because it sure looks like an instance created just for the occasion.
var prototype = Factory.NewTRequired();

И этот код вас никогда не удивит:

// obviously should be false, the code screams "I am creating new instances!"
var eq = object.ReferenceEquals(Factory.NewTRequired(), Factory.NewTRequired());

Известный пример того, как это правило действительно должно было соблюдаться. но не было это DateTime.Now собственность.

person Jon    schedule 15.07.2013

Вместо этого я бы рекомендовал метод:

protected abstract TRequired CreateRequired();

Творение подразумевает происходящую «работу». Это лучше подходит для метода, а не для свойства, поскольку получатель свойства подразумевает что-то, что обычно будет возвращено быстро без выполнения большого количества кода.

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

person Reed Copsey    schedule 15.07.2013

Свойства предназначены для вещей, которые «выглядят как» поля, например, местоположение объекта.

Свойство, которое возвращает новый экземпляр каждый раз, когда вы его получаете, имеет очень плохой дизайн.

Вместо этого вы должны использовать метод.

person SLaks    schedule 15.07.2013