设计模式培训之一:为什么要用单例模式?
查看本人文章索引请通过http://www.cnblogs.com/seesea125/archive/2012/04/17/2453256.html
我们在编程中最常用的模式就是单例模式了,然而单例模式都用在什么场合?为什么不用静态方法而要用单例模式呢?要搞清这些问题,需要从静态方法和非静态方法的区别和联系说起。
一、静态方法常驻内存,非静态方法只有使用的时候才分配内存?
一般都认为是这样,并且怕静态方法占用过多内存而建议使用非静态方法,其实这个理解是错误的。
为什么会这样,先从内存分配开始说起:
托管堆的定义:对于32位的应用程序来说,应用程序完成进程初始化后,CLR将在进程的可用地址空间分配一块保留的地址空间,它是进程(每个进程可使用4GB)中可用地址空间上的一块内存区域,但并不对应任何物理内存,这块地址空间即是托管堆。
托管堆有分为多个区域,其中最重要的是垃圾回收堆(GC Heap)和加载堆(Loader Heap),GC Heap用于存储对象实例,受GC管理;Loader Heap又分为High-Frequency Heap、Low-Frequency Heap和Stub Heap,不同的堆上又存储不同的信息。Loader Heap最重要的信息就是元数据相关的信息,也就是Type对象,每个Type在Loader Heap上体现为一个Method Table(方法表),而Method Table中则记录了存储的元数据信息,例如基类型、静态字段、实现的接口、所有的方法等等。Loader Heap不受GC控制,其生命周期为从创建到AppDomain卸载。(摘自《你必须知道的.Net》)
由此我们就明白了,静态方法和非静态方法,在内存里其实都放在Method Table里了,在一个类第一次被加载的时候,它会在Loader Heap里把静态方法,非静态方法都写入Method Table中,而且Loader Heap不受GC控制,所以一旦加载,GC就不会回收,直到AppDomain卸载
由此我们也明白了,静态方法和非静态方法,他们都是在第一次加载后就常驻内存,所以方法本身在内存里,没有什么区别,所以也就不存在”静态方法常驻内存,非静态方法只有使用的时候才分配内存“这个结论了。
二、静态方法和非静态方法的区别?
在内存中的区别是,非静态方法在创建实例对象时,因为属性的值对于每个对象都各不相同,因此在new一个实例时,会把这个实例属性在GC Heap里拷贝一份,同时这个new出来的对象放在堆栈上,堆栈指针指向了刚才拷贝的那一份实例的内存地址上。而静态方法则不需要,因为静态方法里面的静态字段,就是保存在Method Table里了,只有一份。
因此静态方法和非静态方法,在调用速度上,静态方法速度一定会快点,因为非静态方法需要实例化,分配内存,但静态方法不用,但是这种速度上差异可以忽略不计。
三、为什么要有非静态方法?
早期的结构化编程,几乎所有的方法都是“静态方法”,引入实例化方法概念是面向对象概念出现以后的事情了,区分静态方法和实例化方法不能单单从性能上去理解,创建c++,java,c#这样面向对象语言的大师引入实例化方法一定不是要解决什么性能、内存的问题,而是为了让开发更加模式化、面向对象化。这样说的话,静态方法和实例化方式的区分是为了解决模式的问题。
接下来继续思考,如果我们全部用静态方法,不用非静态方法,不是一样能实现功能吗?是的,没错,但是你的代码是基于对象,而不是面向对象的,因为面向对象的继承和多态,都是非静态方法。
第二个原因是为什么不建议都用静态方法,我们如果多线程的情况下,如果静态方法使用了一个静态字段,这个静态字段可以会被多个线程修改,因此说如果在静态方法里使用了静态变量,这就会有线程安全问题,当然了,就算不是多线程,因为静态字段只有一份,同样会有被其他地方修改的问题。
从这三点我们得出的结论如下:
一、 什么时候用静态方法,什么时候使用非静态方法?
既然静态方法和实例化方式的区分是为了解决模式的问题,如果我们考虑不需要继承和多态的时候,就可以使用静态方法,但就算不考虑继承和多态,就一概使用静态方法也不是好的编程思想。
从另一个角度考虑,如果一个方法和他所在类的实例对象无关,那么它就应该是静态的,否则就应该是非静态。因此像工具类,一般都是静态的。
二、 为什么使用单例模式而不用静态方法?
从面相对象的角度讲:
虽然都能实现目的,但是他们一个是基于对象,一个是面向对象的,就像我们不面相对象也能解决问题一样,面相对象的代码提供一个更好的编程思想。
如果一个方法和他所在类的实例对象无关,那么它就应该是静态的,反之他就应该是非静态的。如果我们确实应该使用非静态的方法,但是在创建类时又确实只需要维护一份实例时,就需要用单例模式了。
比如说我们在系统运行时候,就需要加载一些配置和属性,这些配置和属性是一定存在了,又是公共的,同时需要在整个生命周期中都存在,所以只需要一份就行,这个时候如果需要我再需要的时候new一个,再给他分配值,显然是浪费内存并且再赋值没什么意义,所以这个时候我们就需要单例模式或静态方法去维持一份且仅这一份拷贝,但此时这些配置和属性又是通过面向对象的编码方式得到的,我们就应该使用单例模式,或者不是面向对象的,但他本身的属性应该是面对对象的,我们使用静态方法虽然能同样解决问题,但是最好的解决方案也应该是使用单例模式。
从功能上讲:单例模式可以控制单例数量;可以进行有意义的派生;对实例的创建有更自由的控制;
三、其他:
数据库连接能不能做SingleTon?
如果是简单地把一个connection对象封存在单例对象中,这样是错误的,因此连接池里有多个链接可以用,如果使用SingleTon,那在WEB访问时,就只能用一个数据库链接,那不是死的很惨?
但是链接池可以使用单例模式,初始化的时候创建譬如100个connection对象,然后再需要的时候提供一个,用过之后返回到pool中,我们用单例模式,是保证连接池有且只有一个。
再举个例子,比如DAL层写好一个调用数据库表的类,在BLL层应用此类时,如果每次都new创建的话需要频繁的创建和回收,而DAL层这个类里又没有和对象相关的值变量,所以不需要每次都new一个,这时候就可以用单例模式来创建这个DAL实例。
相关推荐
单例模式是一种设计模式,旨在确保一个类只有一个实例,并提供全局访问点。在单例模式中,类的构造函数是私有的,防止外部直接创建对象,而是通过静态方法获取该类的唯一实例。单例模式的唯一性通常是在进程范围内,...
总的来说,单例模式在某些特定场景下仍然有用,如全局配置、缓存管理等,但应谨慎使用,因为它可能引入了以上提到的问题。在设计时,考虑使用依赖注入、工厂模式或其他设计模式,以提高代码的灵活性、可测试性和可...
### 为什么要在PHP中使用单例模式及其应用实例 #### 一、单例模式的概念与特点 单例模式(Singleton Pattern)是一种常见的设计模式,在软件工程中被广泛应用于确保一个类仅有一个实例,并且该实例可以被全局访问...
#### 二、为什么要使用单例模式? ##### 1、PHP的缺点 PHP作为一种解释型脚本语言,每个PHP页面被解释执行后,所有的相关资源都会被回收。这意味着PHP在语言级别上无法让某个对象常驻内存,这与Java等编译型语言...
首先向关注过我这个系列...这立刻让我想到了最常用也是最简单最容易理解的一个设计模式 单例模式 何为 单例模式 ? 故名思议 即 让 类 永远都只能有一个实例。 由于 示例代码 比较简单 我也加了注释,这里就不在赘述
总的来说,这个项目为学习和理解单例模式和工厂模式在实际开发中的应用提供了一个很好的示例。通过结合这两种模式,可以构建出既保证了对象唯一性,又能灵活应对不同产品创建需求的系统。对于Java开发者来说,深入...
单例模式是软件设计模式中的一种经典模式,它保证了类只有一个实例存在,并提供一个全局访问点。在Java等面向对象编程语言中,单例模式常用于管理共享资源,如数据库连接池、线程池或者配置文件等。结合工厂模式,...
单例模式是软件设计模式中的一种,它保证一...在实际开发中,应谨慎使用单例模式,避免过度使用导致代码维护难度增加。在某些场景下,如依赖注入和微服务架构中,可能需要避免使用单例,以保持更好的灵活性和可测试性。
在这个场景中,我们将探讨如何使用单例模式来创建一个学生管理系统,主要涉及“饿汉式”和“懒汉式”两种实现方式。 **饿汉式单例** 饿汉式单例在类加载时就完成了实例化,因此它是线程安全的。这种方式保证了单例...
**设计模式——单例模式** 在软件工程中,设计模式是一种在特定场景下解决常见问题的标准方案,可以被复用并提升代码质量。单例模式是设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。这种模式...
总结来说,C++11通过`std::mutex`和`std::call_once`等工具,为实现线程安全的单例模式提供了强大支持。这种实现方式既简单又高效,避免了传统实现(如双重检查锁定)可能存在的性能问题。在实际项目中,根据具体...
#### 四、什么情况下使用单例模式? - **控制资源的使用**:通过线程同步来控制资源的并发访问,比如数据库连接池等。 - **控制实例产生的数量**:达到节约资源的目的,如日志对象、缓存管理器等。 - **作为通信...
单例模式是软件设计模式中的一种经典模式,用于确保一个类只有一个实例,并提供一个全局访问点。在Java中,有多种实现单例模式的方法,每种都有其特点和适用场景。接下来,我们将深入探讨这些实现方式。 首先,我们...
单例模式是软件设计模式中的一种经典模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下非常有用,比如控制共享资源、管理配置对象等。下面将详细介绍七种常见的单例模式实现...
在编程领域,设计模式是一种被广泛采用的最佳实践,它提供了在特定情况下解决常见问题的模板。其中,单例模式是一种非常经典且常用的...在C#中,通过合理的封装和访问控制,我们可以方便地创建并使用单例模式的计数器。
这个讲的是单例模式的多种不同实现方式,希望对单例感兴趣的同学看看
在这个特定的场景中,我们讨论的是一个实现了单例模式的日志类,该类专为多线程环境设计,具备日志等级控制、精确的时间戳以及可变长参数和标准格式化输出的功能。 首先,让我们深入了解单例模式。单例模式的主要...
然而,如果涉及类加载器或跨JVM的场景,单例模式的实现就需要更复杂的策略,例如使用`序列化`和`克隆`时需要特殊处理,防止生成额外的实例。另外,如果要考虑服务集群或分布式系统,可能需要采用分布式单例,例如...
单例模式是软件设计模式中的一种,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下都非常有用,比如控制资源的唯一性、管理共享配置或者创建昂贵的对象时避免频繁创建销毁。 ...