Должны ли фабрики устанавливать свойства модели?

В рамках общего SOLID усилия программирования я создал интерфейс factory и абстрактный factory в базовом API-интерфейсе.

Люди уже начинают перегружать фабрики Create method. Проблема в том, что люди перегружают метод Create с помощью свойств модели (и тем самым ожидают, что factory заполнит их).

По-моему, настройка свойств не должна выполняться с помощью factory. Я не прав?

public interface IFactory
{
    I Create<C, I>();
    I Create<C, I>(long id); //<--- I feel doing this is incorrect

    IFactoryTransformer Transformer { get; }
    IFactoryDataAccessor DataAccessor { get; }
    IFactoryValidator Validator { get; }
}

ОБНОВЛЕНИЕ. Для тех, кто не знаком с принципами SOLID, вот несколько из них:

Принцип единой ответственности
В нем говорится, что каждый объект должен иметь одну ответственность и что ответственность должна быть полностью инкапсулирована классом

Открытый/Закрытый Принцип
Смысл этого принципа заключается в том, что когда вы получаете запрос на функцию, которая должна быть добавлена ​​в ваше приложение, вы должны иметь возможность обрабатывать ее без изменения старых классов, только добавляя подклассы и новые реализации.

Принцип инверсии зависимостей
В нем говорится, что вы должны разделить свои программные модули. Чтобы достичь этого, вам нужно изолировать зависимости.

В целом:
Я на 90% уверен, что знаю ответ. Тем не менее, я бы хотел, чтобы хорошие обсуждения у людей, уже использующих SOLID. Спасибо за ваши ценные мнения.

ОБНОВЛЕНИЕ. Итак, что я должен сделать, чтобы SOLID factory должен был делать?

IMHO sOLID factory обслуживает соответствующие объекты-экземпляры... но делает это таким образом, который скрывает сложность создания объекта. Например, если у вас есть модель Employee... вы бы попросили factory предоставить вам подходящую. DataAccessorFactory предоставит вам правильный объект доступа к данным, ValidatorFactory предоставит вам правильный объект проверки и т.д.

Например:

var employee = Factory.Create<ExxonMobilEmployee, IEmployee>();
var dataAccessorLdap = Factory.DataAccessor.Create<LDAP, IEmployee>();
var dataAccessorSqlServer = Factory.DataAccessor.Create<SqlServer, IEmployee>();
var validator = Factory.Validator.Create<ExxonMobilEmployee, IEmployee>();

Взяв пример далее, мы бы...

var audit = new Framework.Audit(); // Or have the factory hand it to you
var result = new Framework.Result(); // Or have the factory hand it to you

// Save your AuditInfo
audit.username = 'prisonerzero';

// Get from LDAP (example only)
employee.Id = 10;
result = dataAccessorLdap.Get(employee, audit);
employee = result.Instance; // All operations use the same Result object

// Update model    
employee.FirstName = 'Scooby'
employee.LastName = 'Doo'

// Validate
result = validator.Validate(employee);

// Save to SQL
if(result.HasErrors)
     dataAccessorSqlServer.Add(employee, audit);

ОБНОВЛЕНИЕ - Так почему я категорически против этого разделения?

Я чувствую, что разделяющие обязанности делают для меньших объектов, меньшие Unit Tests и повышают надежность и обслуживание. Я признаю, что он делает это за счет создания большего количества объектов... но это то, что защищает меня SOLID factory... он скрывает сложность сбора и создания экземпляров указанных объектов.

Ответы

Ответ 1

Я бы сказал, что он придерживается принципа DRY, и до тех пор, пока он прост в использовании, я не вижу, что это проблема/нарушение, Вместо того, чтобы

var model = this.factory.Create();
model.Id = 10;
model.Name = "X20";

разбросаны по всей вашей базе кода, почти всегда лучше иметь его в одном месте. Будущие изменения контракта, рефакторинг или новые требования будут намного проще обрабатывать.

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

И снова, если он сужается до простых назначений (например, в вашем примере), я бы без колебаний сохранил перегрузки, особенно если это то, что вы часто замечаете. Когда ситуация усложняется, это станет признаком обнаружения новых шаблонов и, возможно, тогда вы должны прибегнуть к другим стандартным решениям (например, шаблон построителя).

Ответ 2

Предполагая, что ваш интерфейс factory используется из кода приложения (в отличие от инфраструктурного корня композиции), он фактически представляет собой локатор сервисов, который можно рассматривать как анти-шаблон по отношению к инъекции зависимостей. См. Также Сервис-локатор: роли против механики.

Обратите внимание, что код выглядит следующим образом:

var employee = Factory.Create<ExxonMobilEmployee, IEmployee>();

- это просто синтаксический сахар. Он не устраняет зависимость от конкретной реализации ExxonMobilEmployee.

Вы также можете быть заинтересованы в Слабо типизированные или сильно типизированные каналы сообщений и Сообщение диспетчеризации без местоположения службы (это иллюстрирует, как такие интерфейсы нарушают SRP) и другие публикации Марка Семана.

Ответ 3

Примерно через 6 месяцев опыта в Injection Dependency я обнаружил лишь несколько случаев, когда фабрики должны устанавливать свойства:

  • Если установщик отмечен как internal, и ожидается, что свойства будут установлены один раз только с помощью factory. Обычно это происходит на интерфейсах с только свойствами get ter, реализация которых должна быть создана через factory.

  • Когда модель использует инъекцию свойств. Я редко вижу классы, которые используют инъекцию свойств (я также стараюсь избегать их создания), но когда я вижу его, и необходимый сервис доступен только в другом месте, это случай, когда у вас нет выбора.

В нижней строке оставьте public set от фабрик. Только установите свойства, отмеченные как internal. Пусть клиенты решат, какие свойства им нужно установить, если им разрешено это делать. Это позволит очистить ваши заводы от ненужных функций.