Не смущает ли называть этот класс фабрикой?

Мое понимание фабрики заключается в том, что она инкапсулирует экземпляры конкретных классов, которые все наследуют общий абстрактный класс или интерфейс. Это позволяет отделить клиента от процесса определения того, какой конкретный класс создать, что, в свою очередь, означает, что вы можете добавлять или удалять конкретные классы из своей программы без необходимости изменения кода клиента. Возможно, вам придется изменить фабрику, но фабрика «специально построена» и на самом деле имеет только одну причину для изменения — добавлен/удален конкретный класс.

Я создал несколько классов, которые на самом деле инкапсулируют создание объектов, но по другой причине: объекты трудно создавать. На данный момент я называю эти классы «фабриками», но я обеспокоен тем, что это может быть неправильным названием и сбить с толку других программистов, которые могут посмотреть на мой код. Мои «фабричные» классы не решают, какой конкретный класс создавать, они гарантируют, что серия объектов будет создана в правильном порядке и что правильные классы будут переданы в правильные конструкторы, когда я вызову new().

Например, для проекта MVVM, над которым я работаю, я написал класс, чтобы убедиться, что мой экземпляр SetupView создается правильно. Это выглядит примерно так:

public class SetupViewFactory
{
    public SetupView CreateView(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities)
    {
        var setupViewModel = new SetupViewModel(databaseModel, settingsModel, viewUtilities);
        var setupView = new SetupView();
        setupView.DataContext = setupViewModel;
        return setupView;
    }
}

Не путает ли это название "фабрика"? Он не делает выбор между несколькими возможными конкретными классами, и его тип возвращаемого значения не является интерфейсом или абстрактным типом, но он инкапсулирует создание экземпляра объекта.

Если это не "фабрика", то что?


Изменить

Некоторые люди предположили, что на самом деле это шаблон Builder.

Определение шаблона Builder от dofactory выглядит следующим образом:

Отделите построение сложного объекта от его представления, чтобы один и тот же процесс построения мог создавать разные представления.

Это тоже кажется немного натянутым. Что меня беспокоит, так это «разные представления». Моя цель не в том, чтобы абстрагироваться от процесса построения представления (не то, чтобы это не было достойной целью). Я просто пытаюсь поместить логику для создания определенного представления в одном месте, так что, если какие-либо ингредиенты или процесс создания этого представления изменятся, мне нужно будет изменить только этот один класс. Шаблон компоновщика действительно, кажется, говорит: «Давайте создадим общий процесс для создания представлений, затем вы сможете следовать этому же базовому процессу для любого создаваемого вами представления». Мило, но я здесь не этим занимаюсь.


Изменить 2

Я только что нашел интересный пример в статье Википедии о внедрении зависимостей.

В разделе "Введенная вручную зависимость" он содержит следующий класс:

public class CarFactory {

    public static Car buildCar() {
        return new Car(new SimpleEngine());
    }

}

Это почти в точности то, что я использую (и нет, я не писал вики-статью :)).

Интересно, что это комментарий, следующий за этим кодом:

В приведенном выше коде завод берет на себя ответственность за сборку автомобиля и впрыскивает двигатель в автомобиль. Это освобождает автомобиль от знания о том, как создать двигатель, хотя теперь CarFactory должен знать о конструкции двигателя. Можно было бы создать EngineFactory, но это просто создает зависимости между фабриками. Таким образом, проблема остается, но, по крайней мере, она перенесена в объекты factory или builder. [мой акцент]

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


person devuxer    schedule 16.11.2009    source источник
comment
Чтобы не быть придирчивым, но вы можете переименовать свой метод либо в Create, либо в CreateSetupView.   -  person Mathias    schedule 16.11.2009
comment
Если это все, чего вы пытаетесь достичь, то на самом деле это не какой-то из шаблонов, а просто обновление всего в каком-то классе высшего уровня. Фабрикой это назвать нельзя.   -  person Chap    schedule 17.11.2009
comment
Похоже на шаблон конструктора экземпляра.   -  person s_hewitt    schedule 17.11.2009


Ответы (9)


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

Если судить строго по паттернам GoF, я думаю, что он не соответствует действительности в Factory по двум причинам:

  1. нет семейства связанных/зависимых объектов
  2. конкретный класс действительно указан

Что касается Builder, я думаю, что он упускает аспект разнообразия продуктов.

Когда я преподаю курсы по шаблонам проектирования, я советую студентам смотреть не только на назначение шаблона при попытке определить «наилучшее соответствие», но и на применимость и структуру/участников. Намерение может помочь вам исключить вещи, но применимость и структура/участники — это то, что поможет вам разобраться.

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

person Chris Cleeland    schedule 16.11.2009
comment
Спасибо, @Chris, я согласен с тобой. Мой класс на самом деле не следует ни одному из шаблонов, но, честно говоря, он и не предназначался. Что я действительно хочу знать, так это то, является ли угон общей схемы именования классов из шаблона плохой вещью, если я на самом деле не реализую этот шаблон. Есть мысли по этому поводу? А также, пожалуйста, посмотрите мое второе редактирование моего вопроса. - person devuxer; 17.11.2009
comment
@Chris, также см. мой комментарий к ответу @Jeff Sternal для объяснения того, почему я просто не пишу конструктор для SetupView. - person devuxer; 17.11.2009
comment
Поскольку одной из основных целей шаблонов в целом является определение общего языка, то да, я думаю, неправильно называть его тем, чем он не является, особенно если вы используете другие элементы шаблона. язык шаблонов более правильным образом. Например, мы можем использовать слово «автомобиль» в разговоре и никогда не указывать количество колес, наличие двигателя, дверей, размер и т. д., потому что этот термин воплощает общее понимание. Для меня неправильно называть что-то автомобилем в нашем разговоре, когда на самом деле это полуприцеп. - person Chris Cleeland; 17.11.2009
comment
Кроме того, я прочитал ваше объяснение, почему вы не используете два простых ctor. Первоначально я думал о двух простых ctor и удобном ctor для SetupView, который принимал тот же набор аргументов, что и ctor SetupViewModel, и выполнял всю черновую работу за кулисами. Тем не менее, я понимаю необходимость разделять вещи в вашей ситуации. Я все еще не уверен, что у вас есть фабрика или сборщик GoF, несмотря на параллели в статье в Википедии, но это может не иметь значения. (продолжение) - person Chris Cleeland; 17.11.2009
comment
В конечном счете, важно то, что я считаю важным, так это то, что если нужно потратить много времени на объяснение того, что вы что-то представляете как Factory, Builder, Constructor или ‹вставьте здесь имя шаблона›, то это может быть просто слишком далеко. Назовите это Factory-like или просто объясните, что он делает. Основная идея шаблонов состоит в том, чтобы уменьшить количество явных сообщений, которые должны происходить, поэтому, если вам все равно придется это делать, вы, возможно, запутали проблему хуже, чем вообще не используя имя. - person Chris Cleeland; 17.11.2009

Мне кажется, что у вас есть скорее Builder, чем шаблон Factory.

person Joseph    schedule 16.11.2009

Я думаю, это "Фабрика". Когда я смотрю на объявление класса, я счастлив видеть, что это «Фабрика», и более того, это «Фабрика» объектов SetupView. Так что я знаю, что этот Factory даст мне конкретные и правильно построенные экземпляры SetupView.

person Erkan Haspulat    schedule 16.11.2009

GoF называет это "Builder"

person Victor Sergienko    schedule 16.11.2009
comment
Насколько я знаю, Строителю нужен Директор и Продукт - person Erkan Haspulat; 16.11.2009
comment
Director — это клиентский код, а Product — это, очевидно, SetupView. - person Victor Sergienko; 16.11.2009

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

person Charles Bretana    schedule 16.11.2009

Мне это кажется немного странным. Это не абстрактная фабрика, но и не совсем соответствует шаблону Builder. Для меня было бы наиболее разумным вместо того, чтобы иметь SetupViewFactory с методом CreateView, я бы переместил этот метод в класс SetupView и сделал его статическим. Так что вам бы...

public class SetupView
{
    public static SetupView CreateView(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities)
    {
        var setupViewModel = new SetupViewModel(databaseModel, settingsModel, viewUtilities);
        var setupView = new SetupView();
        setupView.DataContext = setupViewModel;
        return setupView;
    }
}

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

В ответ на комментарий ОП:

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

public class SetupView
{
    public static SetupView CreateView(SetupViewModel model)
    {
        var setupView = new SetupView(); { DataContext = model };
        return setupView;
    }
}
person Jason Punyon    schedule 16.11.2009
comment
@ Джейсон, это определенно перенесет его на заводскую сторону. Вы можете, наоборот, разделить CreateView на отдельные функции и на последнем этапе вернуть SetupView, который будет склоняться к Builder. Я думаю, что это определенно может пойти в обоих направлениях. - person Joseph; 16.11.2009
comment
Интересная идея, но с моим текущим дизайном, я думаю, есть желательное разделение между SetupView и SetupViewModel. Я мог бы захотеть использовать другую ViewModel с моим представлением, что означало бы, что я мог бы просто создать другую фабрику (или отредактировать фабрику), а не возиться с моим представлением. - person devuxer; 16.11.2009
comment
@Jason, спасибо за дополнение к вашему ответу, но теперь мы вернулись к исходной точке :) Весь смысл того, что я пытаюсь сделать, это автоматизировать и обеспечить процесс создания ViewModel, создания View, установки DataContext и вернуть представление, готовое к работе. Что вы сделали здесь, так это переместили часть этой ответственности в класс SetupView, что нормально (может быть, даже хорошо), но теперь любой класс, ответственный за вызов SetupView.CreateView(), все еще нуждается в имени. (И заметьте, у меня есть другие примеры, более сложные, чем этот.) - person devuxer; 16.11.2009
comment
@DanThMan ... тьфу. Какой бордовый. Конечно, это противоположное направление от того, что вы хотите. Я иногда дурак... - person Jason Punyon; 17.11.2009

Почему бы не два класса с простыми конструкторами?

 public class SetupViewModel {
      public SetupViewModel(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities) {
          this.DatabaseModel = databaseModel;
          this.SettingsModel = settingsModel;
          this.ViewUtilities = viewUtilities;
      }
 }

а также

 public class SetupView {         
      public SetupView(SetupViewModel model) {              
          this.DataContext = model;
      }
 }

Таким образом, оба класса ясно указывают, что им нужно построить.

person Jeff Sternal    schedule 16.11.2009
comment
Спасибо, Джефф. Это почти то же самое, что у меня уже есть для SetupViewModel. У меня нет SetupView, задающего собственный DataContext, в основном потому, что это не соглашение, используемое для шаблона MVVM. Идея состоит в том, что View должен быть сгенерирован дизайнерами/художниками с использованием, например, Expression Blend, поэтому лучше иметь как можно меньше кода в коде программной части. Кроме того, вы можете подключить новое представление в любое время, не добавляя код, устанавливающий DataContext. - person devuxer; 17.11.2009
comment
Ах, понял! В этом случае это кажется вполне уместным, хотя я согласен с другими, что это очень близко к тому, чтобы быть строителем. Если вы добавите виртуальный метод CreateSetupView (вызываемый вместо нового оператора), вы там, и это может быть полезно. - person Jeff Sternal; 17.11.2009

Можно назвать его «Волшебник».

person T.E.D.    schedule 16.11.2009

Я склонен согласиться с Джейсоном выше. Для меня это больше похоже на шаблон Builder, но если вы превратите SetupView в интерфейс, он будет больше похож на шаблон Factory. Ключ к шаблону Factory заключается в том, чтобы позволить шаблону Factory выполнять всю работу по решению того, что следует вернуть из вызова функции. Поэтому я думаю, что вам нужно будет переключаться между различными вариантами с учетом входных параметров.

person Excalibur2000    schedule 16.11.2009