静态类和单例模式在实际使用上有什么区别?
两者都可以在不实例化的情况下调用,并且都只提供一个“实例”,但它们都不是线程安全的。除此之外,还有其他区别吗?
静态类和单例模式在实际使用上有什么区别?
两者都可以在不实例化的情况下调用,并且都只提供一个“实例”,但它们都不是线程安全的。除此之外,还有其他区别吗?
你为什么认为单例模式或静态方法不是线程安全的?通常,两者都应该实现为线程安全。
单例模式和一堆静态方法之间的主要区别在于,单例模式可以实现接口(或派生自有用的基类,尽管这在我的经验中比较少见),因此您可以将单例模式像“只是另一个”实现一样传递。
Foo
的接口,你有一个方法需要接受一个 Foo
类型的参数。在这种情况下,调用者可以选择使用单例模式作为实现 - 或者他们可以使用不同的实现。该方法与单例模式解耦了。而如果类只是包含静态方法,则每个想要调用这些方法的代码都与该类紧密耦合,因为它需要指定包含静态方法的类。 - Jon Skeet这个问题的真正答案来自Jon Skeet,在另一个论坛上。
单例模式允许访问单个创建的实例 - 该实例(或者说是对该实例的引用)可以作为参数传递给其他方法,并被视为普通对象。
静态类只允许静态方法。
接口
,但类的静态方法(或例如C#的静态类
)不能实现。单例模式比静态类具有几个优点。首先,单例可以扩展类和实现接口,而静态类不能(它可以扩展类,但不会继承它们的实例成员)。单例可以懒惰地或异步地初始化,而静态类通常在第一次加载时初始化,可能导致类加载器问题。然而,最重要的优点是,单例可以进行多态处理,而不会迫使其用户假设只有一个实例。
静态
类不适用于需要状态的任何内容。它非常适合将一堆函数放在一起,例如项目中的Math
(或Utils
)。因此,类名只是给我们一个提示,告诉我们可以在哪里找到这些函数,仅此而已。
单例模式
是我最喜欢的模式,我使用它来管理单个点上的某些事物。它比静态
类更灵活,可以维护自己的状态。它可以实现接口、继承其他类并允许继承。
我选择静态
和单例
之间的规则:
如果有一堆应该保持在一起的函数,则选择静态
。
任何其他需要对某些资源进行单独访问的内容,都可以实现为单例
。
静态类:
你不能创建静态类的实例。
当包含该类的程序或命名空间被加载时,静态类会被.NET Framework公共语言运行时(CLR)自动加载。
我们不能将静态类传递给方法。
在C#中,我们不能将一个静态类继承到另一个静态类中。
一种具有所有静态方法的类。
更好的性能(静态方法在编译时绑定)。
单例模式:
你可以创建对象的一个实例并重复使用它。
第一次请求时创建单例实例。
你可以创建单例类的对象并将其传递给方法。
单例类不限制继承。
我们可以释放单例类的对象,但无法释放静态类的对象。
方法可以被覆盖。
需要时可以延迟加载(静态类始终已加载)。
我们可以实现接口(静态类无法实现接口)。
静态类是仅具有静态方法的类别,更好的词语是“函数”。静态类所体现的设计风格纯粹是过程化的。
而单例模式则是面向对象设计中特定的一种模式。它是一个对象实例(具有多态等内在可能性),创建过程确保该特定角色在其整个生命周期内只有一个实例。
if( useD3D )
IRenderer::instance = new D3DRenderer
else
IRenderer::instance = new OpenGLRenderer
针对Jon Skeet的回答进行进一步阐述。
单例模式和一堆静态方法之间的最大区别是,单例模式可以实现接口(或者派生自有用的基类,虽然这种情况不太常见),因此您可以将单例模式传递给其他函数,就好像它是“另一个”实现一样。
在进行单元测试时,使用单例模式更容易。无论您在哪里将单例模式作为参数(构造函数、setter或方法)传递,都可以替换一个模拟或存根版本的单例模式。
MySingleton mockOfMySingleton = mock(MySingleton.class)
。 - Mike Rylandernew ClazzToTest(mockSingleton);
- Mike Rylander无法重写方法,但可以使用方法隐藏。(什么是Java中的方法隐藏?即使是Java文档的解释也很困惑)
public class Animal {
public static void foo() {
System.out.println("Animal");
}
}
public class Cat extends Animal {
public static void foo() { // hides Animal.foo()
System.out.println("Cat");
}
}
总之,我只会将静态类用于存放实用方法,并将单例模式用于其他所有内容。
编辑
静态类也是延迟加载的。感谢 @jmoreno (静态类初始化何时发生?)
静态类的方法隐藏。感谢 @MaxPeng。
Animal animal = new Cat();
,那么 animal.foo();
会发生什么? - Luminous_Dev
getInstance()
方法时的开销而变得不太高效(尽管在大多数情况下都无关紧要)。 - too much php