【问题标题】:Singleton Abstract Factory Pattern单例抽象工厂模式
【发布时间】:2012-09-30 12:56:11
【问题描述】:

我想实现一个抽象工厂模式,但也想成为一个单身人士。

class WindowFactory {
protected:
    virtual Scrollbar* createScrollbar() = 0;
};

class MacWindowFactory: public WindowFactory {
    virtual Scrollbar* createScrollbar() {
        //return a instance
    }
    ;
};

class LinuxWindowFactory: public WindowFactory {
    virtual ScrollBar* createScrollbar() {
        //return a instance
    }
    ;
};

有人可以帮我制作这个抽象工厂单例的示例代码吗?

提前致谢。

【问题讨论】:

    标签: c++ design-patterns singleton abstract-factory


    【解决方案1】:

    我设法想出了更优雅的解决方案(目前没有错误检查)。请告诉我你的想法

    #include<iostream>
    #include<map>
    
    class AbstractFactory
    {
    private:
        typedef std::map< std::string, AbstractFactory* > ClientMap;
        static ClientMap s_clientMap;
    public:
        void virtual createScrollbar() = 0;
        void virtual createWindow() = 0;
        static AbstractFactory* createInstance( std::string client );
    protected:
        void Register( std::string, AbstractFactory* );
    };
    
    AbstractFactory::ClientMap AbstractFactory::s_clientMap;
    
    class LinuxFactory: public AbstractFactory
    {
    public:
        void createScrollbar()
        {
            std::cout<<"Scrollbar for Linux"<<std::endl;
        }
    
        void createWindow()
        {
            std::cout<<"WIndow for Linux"<<std::endl;
        }
    private:
        LinuxFactory()
        {
            Register( "Linux", this );
        }
        LinuxFactory( const LinuxFactory& );
        static LinuxFactory s_LinuxFactory;
    
    };
    LinuxFactory LinuxFactory::s_LinuxFactory;
    
    class MacFactory: public AbstractFactory
    {
    public:
        void createScrollbar()
        {
            std::cout<<"Scrollbar for Mac"<<std::endl;
        }
    
        void createWindow()
        {
            std::cout<<"WIndow for Mac"<<std::endl;
        }
    
    private:
        MacFactory()
        {
            Register( "Mac", this );
        }
        MacFactory( const MacFactory& );
        static MacFactory s_MacFactory;
    };
    MacFactory MacFactory::s_MacFactory;
    
    void AbstractFactory::Register( std::string clientName, AbstractFactory* factory )
    {
        s_clientMap.insert( ClientMap::value_type( clientName, factory ) );
    
    }
    AbstractFactory* AbstractFactory::createInstance( std::string client )
    {
    return s_clientMap.find( client )->second;
    
    }
    
    int main()
    {
    AbstractFactory *factory = AbstractFactory::createInstance( "Linux" );
    factory->createScrollbar();
    factory->createWindow();
    }
    

    【讨论】:

      【解决方案2】:

      如果您需要一个真正动态的抽象工厂,您需要在运行时以某种方式对其进行设置。你可以通过一个函数来选择所需的工厂,并使用一个合适的函数来设置实际的单例。在实际应用程序中,您可能会有某种注册函数,您可以在其中注册获取工厂实例的函数(工厂工厂函数)。在下面的示例中,我使用了一个简单的设置,其中可用的工厂在编译时是已知的。

      #include <memory>
      #include <stdexcept>
      #include <string>
      
      class Scrollbar;
      
      class WindowFactory {
      public:
          static void setFactory(std::string const&);
          static Scrollbar* createScrollbar();
          virtual ~WindowFactory() {}
      
      private:
          virtual Scrollbar* doCreateScrollbar() = 0;
      };
      
      class MacWindowFactory
          : public WindowFactory {
          friend void WindowFactory::setFactory(std::string const&);
          virtual Scrollbar* doCreateScrollbar() {
              return 0;
          }
      };
      
      class LinuxWindowFactory
          : public WindowFactory {
          friend void WindowFactory::setFactory(std::string const&);
          virtual Scrollbar* doCreateScrollbar() {
              return 0;
          }
      };
      
      // in WindowFactory.cpp
      
      static std::auto_ptr<WindowFactory>& getPointer()
      {
          static std::auto_ptr<WindowFactory> pointer;
          return pointer;
      }
      
      Scrollbar* WindowFactory::createScrollbar()
      {
          return getPointer().get()
              ? getPointer()->doCreateScrollbar()
              : throw std::runtime_error("WindowFactory not set");
      }
      
      void WindowFactory::setFactory(std::string const& what)
      {
          if (what == "Mac") {
              getPointer() = std::auto_ptr<WindowFactory>(new MacWindowFactory());
          }
          else if (what == "Linux") {
              getPointer() = std::auto_ptr<WindowFactory>(new LinuxWindowFactory());
          }
          else {
              throw std::runtime_error("unknown factory: '" + what + "'");
          }
      }
      

      【讨论】:

      • 这简直太棒了!谢谢。
      【解决方案3】:
      namespace WindowFactory {
            Scrollbar* createScrollbar() {
              #ifdef TARGET_OS_MAC 
               ...
              #elif __linux__ 
               ...
              #endif
            }
      };
      

      我会这样做。

      【讨论】:

      • 谢谢。在这个特定的例子中是的。但我想尽量避免使用宏,尽量坚持面向对象的原则。
      • 他没有使用宏,至少在概念上没有。他只是在检查使用宏机制的编译平台,但实际上并没有任何通常使宏成为错误选择的问题。只是没有编译器以任何其他方式提供此类检查。
      • 附注:对于返回 void 的内容,或者在没有编译代码分支时通常不会导致编译器错误,我还添加了一个最终的“#else #error Missing implementation #endif”来制作一定会引起注意。
      • 请检查我发布的解决方案。谢谢
      • 我同意这种一般风格,但我会更进一步,将它们放在单独的源文件(可能还有头文件)中,并且只编译/包含特定于我平台的文件。