代码之家  ›  专栏  ›  技术社区  ›  Mike

何时不应使用单例模式?(除了显而易见的)

  •  45
  • Mike  · 技术社区  · 14 年前

    我很清楚,您希望使用singleton提供对某些状态或服务的全局访问点。在这个问题中不需要列举单例模式的好处。

    我感兴趣的是,在这种情况下,一开始单身似乎是个不错的选择,但可能会回来咬你。一次又一次,我在书和海报上看到过作者,所以说单件模式通常是一个非常坏的主意。

    “四人帮”表示,在以下情况下,您将希望使用单例:

    • 类必须只有一个实例,并且必须可以从已知的访问点对客户端进行访问。
    • 当唯一的实例应该通过子类进行扩展时,客户机应该能够在不修改代码的情况下使用扩展实例。

    这些观点虽然值得注意,但并不是我所寻求的实际观点。

    有没有人有一套规则或警告,你用来评估你是否 真的,真的 你确定要用单件的吗?

    8 回复  |  直到 8 年前
        1
  •  68
  •   M2tM    9 年前

    dependency injection

    unit tests

    ServiceLocator

    unit testing

    相关链接:

    模式使用与出现

    模式作为概念和术语是有用的,但不幸的是,当真正的模式是根据需要来实现时,人们似乎觉得需要“使用”模式。通常,单子特别是短喇叭,因为它是一个常见的讨论模式。用模式意识设计您的系统,但不要仅仅因为模式存在而专门设计您的系统来屈从于它们。它们是有用的概念工具,但正如你不能仅仅因为可以使用工具箱中的每一个工具一样,你不应该对模式做同样的事情。根据需要使用它们,不要多用或少用。

    单实例服务定位器示例

    #include <iostream>
    #include <assert.h>
    
    class Service {
    public:
        static Service* Instance(){
            return _instance;
        }
        static Service* Connect(){
            assert(_instance == nullptr);
            _instance = new Service();
        }
        virtual ~Service(){}
    
        int GetData() const{
            return i;
        }
    protected:
        Service(){}
        static Service* _instance;
        int i = 0;
    };
    
    class ServiceDerived : public Service {
    public:
        static ServiceDerived* Instance(){
            return dynamic_cast<ServiceDerived*>(_instance);
        }
        static ServiceDerived* Connect(){
            assert(_instance == nullptr);
            _instance = new ServiceDerived();
        }
    protected:
        ServiceDerived(){i = 10;}
    };
    
    Service* Service::_instance = nullptr;
    
    int main() {
        //Swap which is Connected to test it out.
        Service::Connect();
        //ServiceDerived::Connect();
        std::cout << Service::Instance()->GetData() << "\n" << ((ServiceDerived::Instance())? ServiceDerived::Instance()->GetData() :-1);
        return 0;
    }
    
        2
  •  12
  •   Paul Rubel    14 年前

    一个词: testing

    可测试性的一个标志是类的松散耦合,允许您隔离单个类并完全测试它。当一个类使用一个singleton时(我说的是一个经典的singleton,它通过一个静态getInstance()方法强制它自己的奇点),singleton用户和singleton就不可分割地耦合在一起。如果不同时测试单例,就无法再测试用户。

    单身是一场灾难。因为它们是静态的,所以不能用子类将它们除去。因为它们是全局的,所以如果不重新编译或进行一些繁重的提升,就无法轻松地更改它们指向的引用。任何使用singleton的东西都会神奇地得到一个全局引用,这个引用很难控制。这使得很难限制测试的范围。

        3
  •  6
  •   Lou Franco    14 年前

    我见过的singleton最大的错误是你设计了一个单用户系统(比如桌面程序),使用singleton做了很多事情(比如设置),然后你想成为多用户,比如网站或服务。

    这类似于在多线程程序中使用带有内部静态缓冲区的C函数时所发生的情况。

        4
  •  5
  •   Mariusz Jamro    8 年前

    我要说不惜一切代价避免单身。它限制了应用程序的扩展。真正分析您所处理的问题,并考虑可伸缩性,并根据您希望应用程序具有多大的可伸缩性做出决策。

    一天结束时,如果设计不正确,单例会成为资源瓶颈。

        5
  •  3
  •   Steve Townsend    14 年前

    static Globals

        6
  •  0
  •   zerodin    14 年前

        7
  •  0
  •   NoxArt    14 年前