Какие методы должны идти в моем классе фабрики DDD? - PullRequest
12 голосов
/ 04 марта 2009

Я изо всех сил пытаюсь понять, что мой фабричный класс должен делать в моем проекте DDD. Да, фабрика должна использоваться для создания объектов, но что именно она должна делать. Рассмотрим следующий заводской класс:

    public class ProductFactory
    {
        private static IProductRepository _repository;

        public static Product CreateProduct()
        {
            return new Product();
        }

        public static Product CreateProduct()
        {
            //What else would go here?
        }

        public static Product GetProductById(int productId)
        {
            //Should i be making a direct call to the respoitory from here? 
            Greener.Domain.Product.Product p = _repository.GetProductById(productId);
            return p;
        }
    }

Должен ли я делать прямой вызов в хранилище из фабрики?

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

Что мне нужно, чтобы этот класс был завершен, какие еще у меня должны быть методы?

Должен ли я использовать этот класс для создания объекта Product из домена и из репозитория справа?

Пожалуйста, помогите!

Ответы [ 7 ]

11 голосов
/ 04 марта 2009

Должен ли я сделать прямой вызов хранилище изнутри завод

Нет, не используйте фабрику при получении данных, используйте фабрику только при первом ее создании.

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

Передать эти данные на фабрику, если они необходимы для первоначального создания объекта.

Что мне нужно, чтобы сделать этот класс завершите, какие другие методы я должен есть

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

Должен ли я использовать этот класс для создания Объект Product из домена и хранилище справа?

Хранилище предназначено для получения (в некотором смысле создания) существующих объектов, фабрика впервые создает объект.

Изначально многие фабрики мало что делают, кроме вызова конструктора. Но как только вы начинаете рефакторинг и / или создаете более крупные иерархии объектов, фабрики становятся более актуальными.

Объяснение и пример:

Например, в проекте, над которым я работаю, у меня есть базовый класс процессора Excel и много подклассов, реализующих этот базовый класс. Я использую фабрику, чтобы получить правильный, и затем вызываю методы, не зная, какой подкласс был возвращен. (Примечание: я изменил некоторые имена переменных и потрошил / изменил много кода)

Базовый класс процессора:

public abstract class ExcelProcessor
{
      public abstract Result Process(string ExcelFile);
}

Один из подклассов процессора:

public class CompanyAExcelProcessor : ExcelProcessor
{
     public override Result Process(string ExcelFile)
     {
      //cool stuff
     }
}

Factory:

 public static ExcelProcessor CreateExcelProcessor(int CompanyId, int CurrentUserId)
 {
      CompanyEnum company = GetCompanyEnum(CompanyId);
      switch (company)
      {
           case CompanyEnum.CompanyA:
                return new CompanyAExcelProcessor();
           case CompanyEnum.CompanyB:
                return new CompanyBExcelProcessor();
           case CompanyEnum.CompanyC:
                return new CompanyCExcelProcessor(CurrentUserId);
           //etc...
      }
 }

Использование:

ExcelProcessor processor = CreateExcelProcessor(12, 34);
processor.Process();
6 голосов
/ 09 апреля 2009

Будьте осторожны, есть две причины для создания нового объекта: Создание его и регидратация его из базы данных.

Первый случай обрабатывается на заводе. Вы можете предоставить несколько методов для создания объекта на фабрике. Методы фабрики должны возвращать действительные объекты, поэтому вы можете передавать параметры этим методам для предоставления необходимой информации.

Заводской метод также может выбрать фактический тип для создания экземпляра на основе параметров.

Вы не должны смешивать это с регидратацией из базы данных. Этот тип создания экземпляров должен принимать значения из datarow и создавать экземпляр объекта с ним. Я обычно называю это построитель данных вместо фабрика .

Основное отличие состоит в том, что фабрика будет создавать экземпляр объекта с новым идентификатором, а создатель данных - экземпляр объекта с уже существующим идентификатором.

2 голосов
/ 04 марта 2009

Что следует использовать в методе Create вашей фабрики, так это то, что необходимо для того, чтобы перевести новый объект в новый статус.

Теперь для некоторых объектов это означает, что вы ничего не будете делать, кроме этого:

public Product Create()
{
   return new Product();
}

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

И это часть выгоды Фабрики. Теперь у вас есть одно и только одно место, где находится эта специальная логика, и только одно место, где создается новый объект.

1 голос
/ 04 марта 2009

Я лично использовал бы фабрику при нескольких обстоятельствах:

1) Что-то еще определяет, какой тип объектов возвращает эта фабрика (т. Е. Она может возвращать объекты в зависимости от обстоятельств. Например, возвращать объект-заглушку, когда я тестирую, возвращать фактическую реализацию, когда я не тестирую) (это, очевидно, более проблемы Inversion of Control / Dependency Injection - но если вы пока не хотите добавлять контейнеры в свой проект)).

2) У меня есть довольно сложные объекты, которые имеют контейнеры, зависимости, другие отношения и т. Д., И их нужно тщательно строить, чтобы избежать создания нулевых или бессмысленных ссылок. Например, если у меня есть объект Schedule, мне могут понадобиться некоторые поля начала и конца даты - если логика получения, определения этой даты достаточно сложна, я могу не захотеть, чтобы вызывающий класс знал об этом и просто вызвал фабричный метод по умолчанию который создал объект расписания.

Надеюсь, это поможет.

0 голосов
/ 27 сентября 2011

В компоновщике вы можете использовать любую логику, необходимую для информирования инвариантов о ваших объектах, например, использование Java в качестве языка разработки ...

У меня есть объект User, который имеет имя пользователя, пароль и адрес электронной почты, все необходимые атрибуты, поэтому у меня есть:

public class User {

private String username;
private String password;
private String email:

/**
 * @throws IllegalArgumentException if the username is null, the password is null or the
 * email is null.
 */
public User(final String theUsername, final String thePassword, final String theEmail) {
Validate.notNull(theUsername);
Validate.notNull(thePassword);
Validate.notNull(theEmail);

this.username = theUsername;
this.password = thePassword;
this.email = theEmail;
}

// Getters / Setters / equal / hashCode / toString
}

и тогда у меня есть UserBuilder:

public class UserBuilder {
private String username;
private String password;
private String email;

public UserBuilder withUsername(final String theUsername) {
Validate.notNull(theUsername);

this.username = theUsername;

return this;
}

public UserBuilder withPassword(final String thePassword) {
Validate.notNull(thePassword);

this.password = thePassword;

return this;
}

public UserBuilder withEmail(final String theEmail) {
Validate.notNull(theEmail);

this.email = theEmail;

return this;
}

public User build() {
User user = new User(this.username, this.password, this.email);

return user;
}
};

И вы можете использовать строитель следующим образом:

UserBuilder builder = new UserBuilder();

try {
User user = builder.withUsername("pmviva").withPassword("My Nifty Password").withEmail("pmviva@somehost.com").build();
} catch (IllegalArgument exception) {
  // Tried to create the user with invalid arguments
}

Единственной целью фабрики является создание действительных экземпляров объектов. Чтобы не дублировать код создания и администрирования, у вас могут быть свои репозитории для запроса набора строк из базы данных и передачи создания объекта объекту, передавшему данные набора строк.

Надеюсь, это поможет

Спасибо Pablo

0 голосов
/ 16 апреля 2009

@ ThinkBeforeCoding - в примере @ m4bwav фабрика получает действительный идентификатор из вспомогательного метода, но нигде не создает новую запись в слое постоянства. Однако, если я использую столбец идентификаторов, автоматически сгенерированный базой данных, в качестве идентификаторов, создается впечатление, что фабрика должна была бы вызвать хранилище для создания исходного объекта. Можете ли вы прокомментировать, какой метод является «правильным»?

0 голосов
/ 04 марта 2009

В приведенном выше примере мне немного неясно различие между вашей фабрикой и хранилищем. Интересно, не стоит ли просто добавить CreateProduct в качестве метода к хранилищу и использовать DI для вставки хранилища в код, который нуждается в этом? Если фабрика не делает что-нибудь и т. Д ...

Или, если вы просто хотите, чтобы он действовал как глобально зарегистрированный репозиторий, возможно, что-то вроде:

public static IFooRepository Default {get;private set;}
public static void SetRepository(IFooRepository repository) {
    Default = repository;
}

(на мой взгляд, в данном случае кажется более ясным разделить "набор", но вы не должны соглашаться)

и пусть вызывающие абоненты используют var product = YourFactory.Default.CreateProduct(); и т. Д.

...