`
凤舞凰扬
  • 浏览: 66555 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

架构、框架、模式之轻松掌握设计模式(单例模式)

阅读更多
    单例模式可以说是GOF设计模式中最为简单的模式,也是背负骂名最多的模式。不过一直以来,我对许多类似关于它是最烂和反模式的评价却不尽以为然。
    模式本身很简单,除了牵涉多线程安全问题引起的一点罗唆外。所以,我不太想讨论GOF提供的关于该模式的参考实现。我所关注的是它背后带来的对问题的看法和思考方式。
    我们先看看单例模式出现的背景很存在的意义。单例模式通俗来讲就是确保类只有一个实例。那么好,我们问一下,为什么要确保类只有一个实例呢?其实无非是两个方面的作用:一、想控制资源的使用,它又体现在两个方面,其中之一是控制实例数目的产生来节约资源,其二通过线程同步控制资源的并发访问;二、想作为一种通信媒介,在不建立直接关联的条件下让不相关的两个程序进行通信,尤其是多线程。第二点,我说的有些抽象,简单讲吧,就类似于大家基于一个黑板讨论东西,而不关心参与讨论的对象。单例就取了黑板的作用。有人会说,为什么不将同一实例传递给每个使用者就是啊!这样的话,会带来一个问题,就是总是需要一个媒介将该对象传递给所有的使用者。
    简单描述了一下单例模式出现的背景,我们再来看看,网络中对它嗤之以鼻的一些重要的观点:
    1. 使用单例模式有一个很重要的必要条件:在一个系统要求一个类只有一个实例时才应当使用单例模式。反过来说,如果一个类可以有几个实例共存,那么就没有必要使用单例类。
    2.singleton是邪恶的,是反模式(http://www.jdon.com/article/17578.html),为什么说邪恶,因为它有陷井,或者很虚伪,容易诱骗初学者上当。
    3.如果在J2EE的范围内做一次正式的投票,我敢打赌Factory Method、Prototype、Singleton和Bridge绝对是在被淘汰之列,因为它们做的事情已经完全被支持Dependency Injection的容器包办了,程序员再也不需要知道这些模式。所以说呢,“Singleton是邪恶”的或者是一个非伪命题,不过更可能是一个伪问题,因为……谁还需要Singleton呢?你只需要PicoContainer或者Spring Core。
    4.在分布式环境下,比如集群、负载均衡或者多路应用的情况下,单实例是不存在也无法做到的。因为静态方法只能控制在一个环境下的有效。
    说实话,我倒不想去翻案,或者去挑战啥的,不过总是觉得许多言论都存在一些误区或者说隐含的前提。我们依次看一下这些观点吧。第一个观点强调了一个所谓的必要条件,呵呵,这就是它的问题所在了,谁说单例模式有这样的必要条件呢?一个类只有一个实例的适合才应当使用单例模式,呵呵,这话听起来根本就没法驳,有多个实例又怎么去使用单例模式呢?其实啊,这就是最简单的本末倒置了。如果我都知道了我只能有一个实例,我自然不能考虑多例模式。那么考虑使用这个模式的基点究竟在哪个方面呢?其次,什么是有必要,什么是没必要?如果有更好的替代,比如说通过第三方的控制,比如池或者容器来控制实例更合理,那么我们是不是具备什么情况下都可以使用他们呢?必要与否的判定并不是从模式本身出发的,而是从模式应用的场景出发的。
    继续,我们来看第二个问题,singleton is evil,是种反模式,其实来说,是有蛮多道理的,但是问题的本身也似乎不是从模式本身出发,而是从那些不熟悉模式的人盲目使用模式的角度来评说的。看完整篇的文章,我都不清楚这个所谓的陷阱在哪里?singleton不会有线程安全问题的么?GOF的文中从来没有讨论个这个问题的。其实道理很简单啊,线程同步问题归根到底是编程的问题,跟单例又有何关系,多实例就不会有了?问题的关键只是多实例的同步问题比较难以发现,单实例的比较容易发现而已。只是许多应用者根本就没有考虑过所谓的同步问题,所以被发现时怨气都撒在singleton身上了。它,的确有些冤。
    再继续,J2EE做投票,singleton模式将被容器包办,所以该被淘汰。这里其实有两个语境,其一,强调了J2EE和给予所谓Dependency Injection的容器,但是试问一下,singleton模式强调过这样的应用场景么?模式本身只是面向对象的设计思路,跟所谓的语言环境又哪来那么大关联啊?其二,容器真能处理所有的事情么?即使是再强的spring,它的容器也一般用来维护business 的bean实例吧?难道所有应用程序实例的产生都是靠spring的BeanContext或者BeanFactory不成?难道要spring整个侵入业务系统,解决了所谓的问题,才是正道呢?
    最后,第四个问题,有一定的道理,从GOF参考实现的角度,如果我们使用这样的方式去实现我们的应用系统,那么它们是不能在多通路、集群或者负载均衡的情况下应用。这样一来也就是限制了应用系统。但是,提出这样一个问题的人是否又思考过,你对这个模式的探讨是否局限在了GOF提供的实现上呢?模式是解决一类问题的解决方法和实践总结,的确它原始的出处受限于当时的环境,但是这种思路是否依然可以得到扩展和移植呢?一个immutable的实例是否可以做成这样的单实例呢,或者一个由独立系统提供的全局访问控制的mutable实例是否科研做成呢?当然,它在不同的环境会存在多个影子,但是对于每个应用的环境来说,它不是一样作为单个实例出现的么?我们来好好看看单例模式的意图吧: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。我们所做的只是将对意图的理解放在了独立的系统环境中,而不是整个应用系统中。
    有些意思了,好,我们再看看另外一篇帖子,指出为什么singleton is evil。http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx,整的来说,四个观点,我们大致了解一下:
    1.singleton是全局的,它和全局变量又有什么区别呢?全局是不好的,应该通过接口去访问而不是了解类本身。(哈,有些误区,其实是许多人对设计模式的误区:设计模式究竟是运用在何种层次?每个设计模式都是单独出现解决一切问题的么?使用singleton可以选择延迟装载,也完全可以被隔离,对于使用者来说不可知。)
    2.单例模式限制对象的创建,这是不应该的,即使限制也应该通过工厂等其他模式。(呵呵,又是有趣的一点,使用了工厂后的单例模式就不是单例模式?它无法是单例模式和工厂模式的结合罢了。怎么感觉老是拿使用单例模式就都必须直接访问该类一样呢?)
    3.单例将提升类之间的耦合关系。唉,又是这样的论点,隔离一下不就好了么?
    4.只要程序存在多久,单例的状态就维持多久。持久的状态是单元测试的敌人。说实话,没怎么搞明白,第一,单例的状态又不是不能改变,怎么就不能测试。第二难道单元测试还去测试实例的产生和消亡?即使是一个永不消亡的对象又怎么就是单元测试的敌人了。冤!
   
    看到这里,相信好多人准备拍砖了,又是一个死板教条主义的维护者。赶紧澄清啊!不是,真的不是。我从来没有去为单例模式辩护,更不是打死不认帐的角色。我只是在旁,冷静的看看这些,我从来不会因为它是GOF的23种设计模式而乱用,更不会因为某些人的言论而去排斥它。我所知道的,模式只是解决某类特定问题的一种解决方案而已。
    我所想,所说,所做的只是希望会有一些朋友冷静的,思考的去看待它......
分享到:
评论
1 楼 lieyan2024 2012-06-04  
正在学习单例模式, 看了你的文章有收获,有不解.

单例模式确实很方便, 否则我们不得不把本来是单例对象的信息四处传递.
但是单例模式也确实存在问题:

1. 耦合性增加:
   指如果一个类A使用了一个单例B,那么类A就和单例B耦合起来了,类A就没法转移到一个没有单例B的环境下使用.

2. 难于测试:
   单元测试的关键在于独立生成被测试对象,然后独立测试该对象. 如果被测试对象使用了某个单例对象, 那么被测试对象就不容易测试, 因为为了对被测试对象进行完整测试, 我们必须修改单例对象, 而不能使用Mock技术. 在自动测试中, 修改单例对象是很麻烦也是不应该的, 特别是在C++这样的非动态语言中.

你的文章中说到使用"隔离"的方法解决这个问题, 我想多了解一下具体方法.
我做为TDD的忠实拥趸, 也想请教一下你怎么解决测试问题的.

相关推荐

    java 设计模式 mvc模式 单例模式 代理 工厂 简单工厂 第二部分

    在编程领域,设计模式是一种被广泛接受的解决常见问题的模板或最佳实践。Java作为一款广泛应用的面向对象的编程语言,其设计模式的应用...通过学习和熟练掌握这些设计模式,开发者能够更好地应对复杂软件工程的需求。

    小D深入浅出设计模式+框架源码剖析实战

    ├─第一章 旭瑶-小滴架构师成长系列软件设计模式课程介绍 │ 1.2设计模式全家桶课程大纲速览.mp4 │  ├─第二章 想成为架构师的你,不可不知道的设计模式精髓 │ 2.1设计模式的六大原则你知道多少.mp4 │ 2.3...

    C#单例模式详解 C#单例模式详解C#单例模式详解

    单例模式是软件设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。在C#中,单例模式常用于管理共享资源或控制类的实例化过程,以提高性能、节约系统资源,特别是在整个应用程序生命周期内只需要一...

    MVC(单例模式)设计模式

    MVC(Model-View-Controller)设计模式是一种软件设计模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式最初在Smalltalk环境中提出,后来在Java等其他编程语言中...

    程序设计模式与架构

    本文重点介绍了程序设计模式与架构中的几个关键概念,包括创建型模式、结构型模式和行为型模式,以及网站开发架构模式中的MVC框架。设计模式为软件开发提供了一种标准化的方法来解决问题,而架构模式则关注于整体的...

    C++设计模式--基于Qt4开源跨平台开发框架

    通过学习《C++设计模式--基于Qt4开源跨平台开发框架》,开发者不仅可以掌握设计模式的本质和应用场景,还能深入理解Qt4框架的强大功能。结合两者,能够提高代码质量,降低维护成本,同时实现高效且可靠的跨平台应用...

    PHP高级程序设计 模式、框架与测试 中文高清PDF版

    例如,工厂模式、单例模式、观察者模式等,都是在PHP开发中经常用到的设计模式。通过理解这些模式,开发者可以写出更灵活、可扩展的代码,并且能够更好地与其他开发者协作。 再者,“框架”章节会介绍一些流行的PHP...

    NET框架设计 模式、配置、工具.pdf

    这本书涵盖了.NET框架设计的各个方面,包括但不限于设计模式、配置管理以及各种开发工具的使用,旨在帮助开发者提升.NET平台上的编程技能。 **设计模式**是软件工程中的重要概念,它们是经过实践检验的解决方案模板...

    Spring框架的设计理念与设计模式分析之一

    ### Spring框架的设计理念与设计模式分析 #### 一、Spring框架概述 Spring作为一个现代软件开发领域内备受推崇的框架,其强大的功能与灵活性使得它在众多框架中脱颖而出。本文旨在深入探讨Spring框架的设计理念...

    框架总体架构设计说明书

    在本文中,我们将深入探讨框架设计的一些关键知识点,并以“设计模式”为核心概念,来解析框架架构设计的重要性。 设计模式是软件工程中的宝贵经验总结,它们是解决常见设计问题的模板,为开发者提供了一套通用的...

    Spring_框架的设计理念与设计模式分析

    ### Spring框架的设计理念与设计模式分析 #### 一、Spring框架概述 Spring作为一个顶级的Java开发框架,其设计理念和架构模式对于理解和应用该框架至关重要。本文将深入探讨Spring框架的核心设计理念,以及它如何...

    .net 架构师设计模式特训付费版源码一

    《.NET架构师设计模式特训:深度剖析单例模式》 在软件开发中,设计模式是经过时间验证的、解决常见问题的有效方案。其中,单例模式是一种被广泛使用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。...

    Spring框架的设计理念与设计模式分析

    Spring的设计理念和设计模式对于理解和构建高质量的软件系统至关重要。 Spring的核心设计理念是控制反转(Inversion of Control,IoC)和面向接口编程。IoC通过将对象的创建和管理权交给框架,让开发者专注于业务...

    17丨设计模式应用:编程框架中的设计模式.pdf

    GoF(Gang of Four)的23种设计模式,如工厂模式、单例模式、观察者模式等,以及Web开发中常见的MVC(Model-View-Controller)模式,都是在框架设计中广泛应用的。这些模式有助于创建松散耦合、高度内聚的系统,从而...

    Spring框架的设计理念和设计模式分析

    ### Spring框架的设计理念和设计模式分析 #### 一、Spring框架概述 Spring框架自问世以来,因其灵活性、可扩展性和强大的社区支持而迅速成为企业级Java应用开发的标准框架之一。Spring框架的核心价值在于其轻量级...

    java之设计模式--各种设计模式解析

    Java设计模式是面向对象编程中的一种最佳实践,用于解决常见的软件设计问题,提高代码的可重用性、可维护性和可扩展性...因此,深入学习和掌握设计模式不仅能够提升个人的编程技能,也有助于团队协作和项目的成功实施。

    侯捷李建中的设计模式讲义

    《侯捷李建中的设计模式讲义》是两位IT界知名专家对于设计模式的深入讲解,结合了.NET、C#、Java...通过深入学习,开发者不仅可以掌握设计模式的精髓,还能在日常工作中更高效地解决复杂问题,提升代码质量和可维护性。

    PHP高级程序设计:模式框架与测试

    - **设计模式**:书中深入介绍了设计模式的概念,如单例模式、工厂模式、观察者模式等,这些模式在实际项目中被广泛使用,能够提高代码的可读性和可维护性。 - **架构模式**:讨论了如MVC(模型-视图-控制器)模式...

Global site tag (gtag.js) - Google Analytics