为什么要有单例设计模式 为什么要用单例模式

我们编程中最常用的模式是singleton模式,但是singleton模式用在哪里呢?为什么使用单例模式而不是静态方法?要理解这些问题,需要从静态方法和非静态方法的区别和联系入手 。
I .静态方法内存驻留 。非静态方法只有在使用时才分配内存?
一般认为是这样 , 因为怕静态方法占用内存太多,建议使用非静态方法 。其实这种理解是错误的 。
为什么会这样?让我们从内存分配开始:
托管堆的定义:对于32位应用,应用完成进程初始化后,CLR会在进程的可用地址中分配一个保留地址空 。它是进程的可用地址空之间的内存区域(每个进程可以使用4GB),但不对应任何物理内存 。这个地址
托管堆分为几个区域,其中最重要的是垃圾收集堆(GC Heap)和加载器堆 。GC堆用于存储对象实例,由GC管理 。加载器堆分为高频堆、低频堆和存根堆,不同的堆存储不同的信息 。加载器堆最重要的信息是元数据相关的信息,也就是类型对象 。每种类型都表示为加载器堆上的一个方法表,存储的元数据信息(如基类型、静态字段、实现的接口、所有方法等)都记录在方法表中 。加载器堆不受GC控制,其生命周期是从创建到AppDomain卸载 。(摘自《你必须知道 。净”)
由此可以看出,静态方法和非静态方法实际上都是放在内存中的方法表中的 。当一个类第一次加载时,它会将静态方法和非静态方法都写入加载器堆中的方法表 , 而加载器堆不受GC控制,所以一旦加载,在AppDomain卸载之前,GC不会回收它 。
由此可以看出,静态方法和非静态方法都是在第一次加载后内存常驻,所以方法本身在内存中没有区别,所以不存在“静态方法内存常驻,非静态方法只在使用时分配内存”的结论 。
二、静态和非静态方法的区别?
内存上的区别在于,当非静态方法创建实例对象时 , 由于每个对象的属性的值是不同的 , 所以在创建新的实例时,会在GC Heap中做一个实例属性的副本,新创建的对象会放在堆栈上,堆栈指针会指向刚刚复制的实例的内存地址 。但是,静态方法是不必要的,因为静态方法中的静态字段存储在方法表中,只有一个副本 。
【为什么要有单例设计模式 为什么要用单例模式】所以静态方法和非静态方法 , 在调用速度上,静态方法会更快,因为非静态方法需要实例化和内存分配,而静态方法不用,但是速度上的差异可以忽略 。
三 。为什么要有非静态的方法?
在早期的结构化程序设计中,几乎所有的方法都是“静态方法” , 实例化方法概念的引入是在面向对象概念出现之后 。静态方法和实例化方法的区别不能单从性能上理解 。创造了C、Java、C #等面向对象语言的大师们引入实例化方法并不是为了解决什么性能和内存问题,而是为了让开发更加模块化和面向对象 。这样,静态方法和实例化方法的区别就是解决模式的问题 。
接下来,我们继续思考 。如果我们都用静态方法而不是非静态方法,难道不能实现同样的功能吗?是的 , 没错,但是你的代码是基于对象的 , 不是面向对象的,因为面向对象的继承和多态都是非静态方法 。
第二个原因是为什么我们不推荐所有的静态方法 。如果我们是多线程 , 如果一个静态方法中使用了一个静态字段,这个静态字段可以被多线程修改 。因此,如果在静态方法中使用静态变量,就会出现线程安全问题 。当然 , 即使不是多线程,因为只有一个静态字段,还是会有被其他地方修改的问题 。
从这三点出发,我们得出以下结论:
一、什么时候用静态方法,什么时候用非静态方法?
既然静态方法和实例化的区别是为了解决模式的问题,那么如果考虑到不需要继承和多态,就可以使用静态方法 。但是 , 在不考虑继承和多态的情况下使用静态方法并不是一个好的编程思路 。
另一方面,如果一个方法与其类的实例对象无关,那么它应该是静态的,否则它应该是非静态的 。所以和工具一样 , 一般都是静态的 。
第二 , 为什么要用singleton模式而不是静态方法?
从面部物体的角度来看:
虽然都可以达到目的,但是一个是基于对象的,一个是面向对象的 。正如我们可以不用面对对象就能解决问题一样,面向对象的代码提供了更好的编程思想 。
如果一个方法与其类的实例对象无关 , 那么它应该是静态的,否则它应该是非静态的 。如果我们真的应该使用非静态方法,但在创建类时只需要维护一个实例,我们就需要使用singleton模式 。

推荐阅读