Фабричный шаблон в C ++ - делать это правильно? - PullRequest
12 голосов
/ 14 февраля 2011

Я относительно новичок в «шаблонах проектирования», поскольку они упоминаются в формальном смысле. Я не был профессионалом очень долго, поэтому я довольно новичок в этом.

У нас есть чистый базовый класс виртуального интерфейса. Этот интерфейсный класс, очевидно, предназначен для определения того, какую функциональность должны делать его производные дочерние элементы. Текущее использование и ситуация в программном обеспечении диктуют, какой тип производного дочернего элемента мы хотим использовать, поэтому я рекомендовал создать оболочку, которая будет сообщать, какой тип производного дочернего элемента мы хотим, и возвращать указатель Base, указывающий на новый производный объект. Эта обертка, насколько я понимаю, фабричная.

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

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

Правильно ли я считаю, что фабрике действительно нужно быть оберткой вокруг базового класса, а не базой, действующей как фабрика?

Ответы [ 5 ]

15 голосов
/ 14 февраля 2011

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

лучший способ реализовать шаблон фабрики - это отделить интерфейс вашего класса от фабрики.

Ниже приведен очень простой (и неполный) пример:

class MyInterface
{
public:
    virtual void MyFunc() = 0;
};

class MyImplementation : public MyInterface
{
public:
    virtual void MyFunc() {}
};

class MyFactory
{
public:
    static MyInterface* CreateImplementation(...);
};
4 голосов
/ 14 февраля 2011

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

3 голосов
/ 14 февраля 2011

Да, статический метод фабрики в интерфейсе (базовый класс) требует, чтобы он знал все возможные экземпляры. Таким образом, вы не получаете никакой гибкости, которую должен принести шаблон Factory Method.

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

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

2 голосов
/ 14 февраля 2011

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

1 голос
/ 14 февраля 2011

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

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

Поэтому обычно лучше разделить фабричную часть на отдельный класс.

...