单例模式 VS 静态方法
我们在设计程序经常会有这种需求, 某个类里的方法能够全局访问, 在这种情况下有两种实现方案:
单例模式 (Singleton)
静态方法
但是, 对于这两种实现方式, 那种更好呢?
[TOC]
在国内论坛上看了一下其他的一些看法
关于这个问题, 下面是一些同仁的观点:
观点一: (单例)
单例模式比静态方法有很多优势:
首先, 单例可以继承类, 实现接口, 而静态类不能 (可以集成类, 但不能集成实例成员) ;
其次, 单例可以被延迟初始化, 静态类一般在第一次加载是初始化;
再次, 单例类可以被集成, 他的方法可以被覆写;
最后, 或许最重要的是, 单例类可以被用于多态而无需强迫用户只假定唯一的实例.
举个例子, 你可能在开始时只写一个配置, 但是以后你可能需要支持超过一个配置集, 或者可能需要允许用户从外部从外部文件中加载一个配置对象, 或者编写自己的. 你的代码不需要关注全局的状态, 因此你的代码会更加灵活.
观点二: (静态方法)
静态方法中产生的对象, 会随着静态方法执行完毕而释放掉, 而且执行类中的静态方法时, 不会实例化静态方法所在的类. 如果是用 singleton, 产生的那一个唯一的实例, 会一直在内存中, 不会被 GC 清除的 (原因是静态的属性变量不会被 GC 清除), 除非整个 JVM 退出了.
观点三: (Good!)
由于 DAO 的初始化, 会比较占系统资源的, 如果用静态方法来取, 会不断地初始化和释放, 所以我个人认为如果不存在比较复杂的事务管理, 用 singleton 会比较好.
总结:
大家对这个问题都有一个共识: 那就是实例化方法更多被使用和稳妥, 静态方法少使用.
误解
有时候我们对静态方法和实例化方法会有一些误解.
大家都以为"静态方法常驻内存, 实例方法不是, 所以静态方法效率高但占内存."
事实上, 他们都是一样的, 在加载时机和占用内存上, 静态方法和实例方法是一样的, 在类型第一次被使用时加载. 调用的速度基本上没有差别.
大家都以为"静态方法在堆上分配内存, 实例方法在堆栈上"
事实上所有的方法都不可能在堆或者堆栈上分配内存, 方法作为代码是被加载到特殊的代码内存区域, 这个内存区域是不可写的. 方法占不占用更多内存, 和它是不是static没什么关系.
因为字段是用来存储每个实例对象的信息的, 所以字段会占有内存, 并且因为每个实例对象的状态都不一致 (至少不能认为它们是一致的) , 所以每个实例对象的所以字段都会在内存中有一分拷贝, 也因为这样你才能用它们来区分你现在操作的是哪个对象.
但方法不一样, 不论有多少个实例对象, 它的方法的代码都是一样的, 所以只要有一份代码就够了. 因此无论是static还是non-static的方法, 都只存在一份代码, 也就是只占用一份内存空间.
同样的代码, 为什么运行起来表现却不一样?这就依赖于方法所用的数据了. 主要有两种数据来源, 一种就是通过方法的参数传进来, 另一种就是使用class的成员变量的值……
大家都以为"实例方法需要先创建实例才可以调用, 比较麻烦, 静态方法不用, 比较简单"
事实上如果一个方法与他所在类的实例对象无关, 那么它就应该是静态的, 而不应该把它写成实例方法, 所以所有的实例方法都与实例有关, 既然与实例有关, 那么创建实例就是必然的步骤, 没有麻烦简单一说.
当然你完全可以把所有的实例方法都写成静态的, 将实例作为参数传入即可, 一般情况下可能不会出什么问题.
从面向对象的角度上来说, 在抉择使用实例化方法或静态方法时, 应该根据是否该方法和实例化对象具有逻辑上的相关性, 如果是就应该使用实例化对象 反之使用静态方法. 这只是从面向对象角度上来说的.
如果从线程安全、性能、兼容性上来看 也是选用实例化方法为宜.
我们为什么要把方法区分为: 静态方法和实例化方法?
如果我们继续深入研究的话, 就要脱离技术谈理论了.
早期的结构化编程, 几乎所有的方法都是"静态方法", 引入实例化方法概念是面向对象概念出现以后的事情了, 区分静态方法和实例化方法不能单单从性能上去理解, 创建 c++,Java,c# 这样面向对象语言的大师引入实例化方法一定不是要解决什么性能、内存的问题, 而是为了让开发更加模式化、面向对象化. 这样说的话, 静态方法和实例化方式的区分是为了解决模式的问题.
拿别人一个例子说事: 比如说"人"这个类, 每个人都有姓名、年龄、性别、身高等, 这些属性就应该是非静态的, 因为每个人都的这些属性都不相同; 但人在生物学上属于哪个门哪个纲哪个目等, 这个属性是属于整个人类, 所以就应该是静态的——它不依赖与某个特定的人, 不会有某个人是"脊椎动物门哺乳动物纲灵长目"而某个人却是"偶蹄目"的
在国外一些论坛的看法(重点)
什么时候使用静态类代替 singleton
这里有几个很好的静态类比singleton更好的应用场景. 最基本的例子就是在 Java 中的 java.lang.Math 类的实现方式, Math 类就是用过静态方法来实现的,而不是单例来实现的.
总结: 如果你的 singleton 不提维持任何状态, 仅仅是提供全局的访问, 这个时候就适合用静态类, 这样速度也更快, 因为 static bind 在编译期间 (compile during). 记住不经意维持子类的状态, 尤其是在并发的情况下, 多个线程并发修改,这容易导致不容易发现的 race condition 关于 race condition.
静态类适用于一些工具类, 其他的如单个访问资源就可以用 singleton.
静态类和 singleton 之间的区别
static 类有更好的访问效率 (Static class provides better performance than Singleton pattern, because static methods are bonded on compile time)
singleton 比 static class 更容易测试, 那个容易模拟 (mock), 哪个就容易测试, singleton 很容易用 JUnit测试, 因为你能够传递 mock 对象, 当 singleton 需要的时候 (作为方法参数或者构造函数参数)
如果你的需求是维护 (maintain) 状态, 那么 singleton 比 static class 更好, 如果使用 static class 会出现一些问题
singleton 支持延迟加载, 而 static class 则不支持这样的特性, 在重量级的对象, 延迟加载就显得非常重要
在一些依赖注入 (Dependency injection framework) 的框架, 它能够很好的管理 singleton 对象, 例如 spring
singleton 相对于静态类的一些高级特点
singleton 对于 static class 主要的优点是更加面向对象.
对于 singleton 你可以使用继承 (Inheritance) 和多态 (polymorphism) 来继承一个基类, 实现一个接口, 提供不同功能 的实现.
例如, Java 中 java.lang.Runtime, 该类就是一个 singleton 的, 调用 getRuntime(), 基于不同的 JVM,返回不同的实现对象, 针对一个一个 JVM,确保只有一个 Runtime 对象, 如果使用 static class 就不能很好的来实现这样的功能了.
Last updated