Разве шаблон фабрики - это не то же самое, что глобальное состояние?

StackOverflow https://stackoverflow.com/questions/616573

Вопрос

Допустим, у меня есть такой класс:

class MonkeyFish
{
   MonkeyFish( GlobalObjectA & a, GlobalObjectB & b, GlobalObjectC & c);

   private:
     GlobalObjectA & m_a;
     GlobalObjectB & m_b;
     GlobalObjectC & m_c;
}

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

GlobalObjectA a;
GlobalObjectB b;
GlobalObjectC c;

int main()
{
  MonkeyFish * monkey_fish = new MonkeyFish(a, b, c);
  monkey_fish->go();
}

С другой стороны, если у меня есть MonkeyFishFactory , мне кажется, что я должен это сделать:

GlobalObjectA a;
GlobalObjectB b;
GlobalObjectC c;

int main()
{
  MonkeyFishFactory mf_factory(a, b, c);
  MonkeyFish * monkey_fish = mf_factory.buildMonkeyFish("Bob");
  monkey_fish->go();
}
<Ол>
  • У меня все еще есть глобальные объекты.

  • Даже если сама MonkeyFishFactory сама создала GlobalObjects внутри (поэтому они теперь находятся внутри MonkeyFishFactory вместо истинных глобальных переменных), похоже, что сама MonkeyFishFactory все еще остается должен быть глобальным объектом, чтобы иметь к нему доступ в любое время, когда я захочу создать MonkeyFish .

  • Разве в этом случае шаблон Factory не совпадает с глобальным состоянием?

    (В настоящее время я работаю в предположении, что глобальное состояние - это плохая вещь, а устранение - хорошая.)

    Это было полезно?

    Решение

    Вы здесь путаете понятия?

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

    То, что вы описываете, представляет собой смесь Singleton (или MonoState) и Factory. Ваша фабрика имеет состояние, поэтому она не может быть статичной. В этом случае вам нужно будет применить что-то вроде шаблона Singleton для управления созданием одного экземпляра Factory с соответствующими глобальными переменными, скрытыми внутри него:

    class IMonkeyFish {
    public:
        virtual ~IMonkeyFish() = 0;
        virtual void go() = 0;
    };
    
    class Factory {
    public:
        static Factory& instance();
        IMonkeyFish* createMonkeyFish();
    protected:
        Factory(GlobalObjectA& a, GlobalObjectB& b, GlobalObjectC& c);
    private:
        static Factory *theInstance;
        GlobalObjectA&  instanceOfA;
        GlobalObjectB&  instanceOfB;
        GlobalObjectC&  instanceOfC;
    };
    
    Factory& factory = Factory::instance();
    IMonkeyFish* fishie = factory.createMonkeyFish();
    fishie->go();
    

    Шаблон Singleton управляет созданием экземпляра фабрики. Шаблон Factory скрывает детали, связанные с созданием объектов, которые реализуют интерфейс IMonkeyFish . Хорошая вещь (TM) - это скрытие глобального состояния и отделение MonkeyFish от конкретных деталей при создании экземпляра.

    Использование или правильность использования материала Singleton - это совсем другая проблема. Вероятно, вокруг этого тоже есть куча потоков.

    Другие советы

    Глобальное состояние само по себе не является плохим. Публичное глобальное состояние - это плохо. Шаблон Factory помогает инкапсулировать глобальное состояние, что является хорошей вещью.

    На фабрике нет глобального состояния. Он просто создает объекты. Так как это не любое состояние на заводе. Это нормально, чтобы быть глобальным.

    Вам не нужно оставлять глобальные объекты. Обезьянья рыбная фабрика должна создавать такие GlobalOjectA | B | C по требованию. Используя переключатель или метод внутри, чтобы определить, какой из них.

    Вы инкапсулировали контроль над созданием объектов на фабрике. Вы хотите, чтобы детали вашего экземпляра были скрыты, а не воспроизводились везде, где вам нужна новая MonkeyFish. Подумайте о тестировании, единственной ответственности и законе Деметры. Почему вашему классу, который хочет использовать MonkeyFish, нужно знать что-либо о работе, необходимой для его создания. Что если вы хотите протестировать MonkeyFish? Как бы вы это сделали, если бы у вас не было инкапсулированных деталей создания?

    Задача фабричного класса - создать экземпляр объекта и передать его вызывающей стороне; не выбирать какой глобальный экземплярный объект использовать. Итак, ваш фабричный пример неверен. Должно быть:

    int main()
    {
      MonkeyFish * monkey_fish = MonkeyFishFactory::buildMonkeyFish("Bob");
      monkey_fish->go();
    }
    

    Обратите внимание, глобальные объекты отсутствуют, и MonkeyFishFactory не создан.

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

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

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

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

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top