Factory Шаблон на С++ - это правильно?

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

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

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

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

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

Ответ 1

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

Лучшим способом реализации шаблона factory является разделение вашего класса интерфейса от вашего factory.

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

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

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

class MyFactory
{
public:
    static MyInterface* CreateImplementation(...);
};

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

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

Как правило, лучше разделить часть factory на отдельный класс.