静态类和单例模式之间存在什么真正(即实用)的区别?
两者都可以不实例化地调用,都只提供一个“实例”,并且它们都不是线程安全的。还有其他区别吗?
singleton
对象,static
是一个非OO实体。
静态类和单例模式之间存在什么真正(即实用)的区别?
两者都可以不实例化地调用,都只提供一个“实例”,并且它们都不是线程安全的。还有其他区别吗?
singleton
对象,static
是一个非OO实体。
Answers:
是什么让您说单例或静态方法不是线程安全的?通常,两者都应实现为线程安全的。
单例和一堆静态方法之间的最大区别在于,单例可以实现接口(或从有用的基类派生,尽管根据我的经验,这种情况不那么常见),因此您可以将单例当作“只是另一个实施。
Foo
,并且您有一个将a Foo
作为参数的方法。通过该设置,调用者可以选择使用单例作为实现,也可以使用其他实现。该方法与单例解耦。将其与类仅具有静态方法的情况进行比较-每个要调用这些方法的代码都与该类紧密耦合,因为它需要指定哪个类包含静态方法。
真正的答案是Jon Skeet,在另一个论坛上。
单例允许访问创建的单个实例-可以将该实例(或更确切地说,对该实例的引用)作为参数传递给其他方法,并视为普通对象。
静态类仅允许使用静态方法。
interface
用Singleton类实现,但不能使用类的静态方法(例如C#static class
)。与静态类相比,Singleton模式具有多个优点。首先,单例可以扩展类并实现接口,而静态类则不能(它可以扩展类,但不继承其实例成员)。单例可以延迟或异步初始化,而静态类通常在首次加载时进行初始化,从而导致潜在的类加载器问题。但是,最重要的优点是,可以以多态方式处理单例,而不必强迫其用户假定只有一个实例。
static
类不适合任何需要状态的内容。对于将一堆功能放在一起Math
(或Utils
在项目中)很有用。因此,类名只是为我们提供了一个线索,在这里我们可以找到函数,仅此而已。
Singleton
是我最喜欢的模式,我用它来单点管理。它比static
类更灵活,并且可以维护其状态。它可以实现接口,从其他类继承并允许继承。
我在static
和之间选择的规则singleton
:
如果有一堆应该保持在一起的功能,那static
就是选择。需要对某些资源进行单一访问的任何其他内容都可以实现为singleton
。
State
来说,就是对象的不同属性的组合,这些属性通常会随着时间而变化。您可以对Google进行正式定义。
静态类别:-
您不能创建静态类的实例。
加载包含该类的程序或名称空间时,由.NET Framework公共语言运行时(CLR)自动加载。
静态类不能具有构造函数。
我们不能将静态类传递给方法。
我们不能在C#中将Static类继承到另一个Static类。
具有所有静态方法的类。
性能更好(静态方法在编译时绑定)
单身人士:-
您可以创建该对象的一个实例并重新使用它。
当用户请求时,首次创建Singleton实例。
Singleton类可以具有构造函数。
您可以创建单例类的对象并将其传递给方法。
Singleton类未说明继承的任何限制。
我们可以处理单例类的对象,但不能处理静态类的对象。
方法可以被覆盖。
可以在需要时延迟加载(始终加载静态类)。
我们可以实现接口(静态类不能实现接口)。
静态类是仅具有静态方法的类,对此更好的词应该是“函数”。静态类中体现的设计风格纯粹是过程性的。
另一方面,单例是面向对象设计的特定模式。它是一个对象的实例(具有其固有的所有可能性,例如多态性),并且创建过程确保该特定角色在其整个生命周期中只有一个实例。
在单例模式中,您可以将单例创建为派生类型的实例,而不能使用静态类来实现。
快速示例:
if( useD3D )
IRenderer::instance = new D3DRenderer
else
IRenderer::instance = new OpenGLRenderer
单例和一堆静态方法之间的最大区别是,单例可以实现接口(或从有用的基类派生,尽管这是不太常见的IME),因此您可以将单例作为“只是另一个”实现来传递。
在单元测试课程时,单例更容易使用。无论您在何处传递单例作为参数(构造函数,setter或方法),都可以替代模拟的或存根的单例版本。
MySingleton mockOfMySingleton = mock(MySingleton.class)
。
new ClazzToTest(mockSingleton);
这是一篇好文章:http : //javarevisited.blogspot.com.au/2013/03/difference-between-singleton-pattern-vs-static-class-java.html
不能覆盖方法,但可以使用方法隐藏。(Java中隐藏的方法是什么?甚至JavaDoc的解释也令人困惑)
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");
}
}
总之,我只会使用静态类来保存util方法,而将Singleton用于其他所有内容。
编辑
静态类也被延迟加载。谢谢@jmoreno(什么时候进行静态类初始化?)
隐藏静态类的方法。谢谢@MaxPeng。
Animal animal = new Cat();
那animal.foo();
会发生什么呢?
我不是一个很棒的面向对象理论家,但是据我所知,我认为静态类与Singletons相比唯一缺乏的OO特性是多态性。但是,如果您不需要它,则使用静态类当然可以具有继承(不确定接口实现)以及数据和函数封装。
Morendil的评论“静态类中体现的设计风格纯粹是程序性的”,我可能是错的,但我不同意。在静态方法中,您可以访问静态成员,这与访问其单个实例成员的单例方法完全相同。
编辑:
我现在实际上在想的另一个区别是,静态类在程序启动时实例化,并且在程序的整个生命周期中都存在,而单例则在某个时刻显式实例化,并且也可以销毁。
*或者我认为它可能会在首次使用时实例化,具体取决于语言。
为了说明乔恩的观点,如果Logger是静态类,则无法完成以下显示的操作。该类SomeClass
希望将ILogger
实现的实例传递到其构造函数中。
单例类对于进行依赖注入很重要。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var someClass = new SomeClass(Logger.GetLogger());
}
}
public class SomeClass
{
public SomeClass(ILogger MyLogger)
{
}
}
public class Logger : ILogger
{
private static Logger _logger;
private Logger() { }
public static Logger GetLogger()
{
if (_logger==null)
{
_logger = new Logger();
}
return _logger;
}
public void Log()
{
}
}
public interface ILogger
{
void Log();
}
}
Singleton实例化,仅实例化了一个实例,因此Singleton中的单个实例。
静态类不能由其自身实例化。
主要区别在于:
从测试的角度来看,单例是更好的方法。与静态类不同,单例可以实现接口,您可以使用模拟实例并将其注入。
在下面的示例中,我将对此进行说明。假设您有一个isGoodPrice()方法,该方法使用getPrice()方法,并且将getPrice()作为单例方法实现。
提供getPrice功能的单例:
public class SupportedVersionSingelton {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){
if(instance == null){
instance = new SupportedVersionSingelton();
}
return instance;
}
@Override
public int getPrice() {
// calculate price logic here
return 0;
}
}
使用getPrice:
public class Advisor {
public boolean isGoodDeal(){
boolean isGoodDeal = false;
ICalculator supportedVersion = SupportedVersionSingelton.getInstance();
int price = supportedVersion.getPrice();
// logic to determine if price is a good deal.
if(price < 5){
isGoodDeal = true;
}
return isGoodDeal;
}
}
In case you would like to test the method isGoodPrice , with mocking the getPrice() method you could do it by:
Make your singleton implement an interface and inject it.
public interface ICalculator {
int getPrice();
}
最终的Singleton实施:
public class SupportedVersionSingelton implements ICalculator {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){
if(instance == null){
instance = new SupportedVersionSingelton();
}
return instance;
}
@Override
public int getPrice() {
return 0;
}
// for testing purpose
public static void setInstance(ICalculator mockObject){
if(instance != null ){
instance = mockObject;
}
测试类别:
public class TestCalculation {
class SupportedVersionDouble implements ICalculator{
@Override
public int getPrice() {
return 1;
}
}
@Before
public void setUp() throws Exception {
ICalculator supportedVersionDouble = new SupportedVersionDouble();
SupportedVersionSingelton.setInstance(supportedVersionDouble);
}
@Test
public void test() {
Advisor advidor = new Advisor();
boolean isGoodDeal = advidor.isGoodDeal();
Assert.assertEquals(isGoodDeal, true);
}
}
如果我们选择使用静态方法来实现getPrice(),则很难模拟getPrice()。您可以使用电源模拟来模拟静态,但并非所有产品都可以使用它。
一个显着的区别是Singletons附带的实例化不同。
对于静态类,它是由CLR创建的,我们无法对其进行控制。如果是单例,则在尝试访问该对象的第一个实例上实例化该对象。
在许多情况下,这两者没有实际区别,尤其是在单例实例从不改变或非常缓慢地改变(例如保持配置)的情况下。
我想说的最大区别是,单例仍然是普通的Java Bean,与专门针对静态的Java类相反。因此,在更多情况下可以接受单例。实际上,它是默认的Spring Framework的实例化策略。使用者可能知道也可能不知道这是一个单例,只是像对待普通Java bean一样对待它。如果需求发生变化,而需要将一个实例作为原型,就像我们在Spring中经常看到的那样,则可以完全无缝地完成它,而无需对使用者进行任何代码更改。
之前有人提到静态类应该纯粹是过程性的,例如java.lang.Math。在我看来,此类绝不应该被传递,并且除了静态final以外,它们不应该包含任何其他属性。对于其他所有内容,请使用单例,因为它更加灵活且易于维护。
我们有连接后端的数据库框架。为避免多个用户之间的脏读,我们使用单例模式来确保我们在任何时间都可以使用单个实例。
在c#中,静态类无法实现接口。当单个实例类需要实现用于商业合同或IoC目的的接口时,这是我在不使用静态类的情况下使用Singleton模式的地方
Singleton提供了一种在无状态方案中维护状态的方法
希望对您有帮助。
一个。序列化-静态成员属于该类,因此无法序列化。
b。尽管我们已经将构造函数设为私有,但是静态成员变量仍将被携带到子类中。
C。我们不能进行延迟初始化,因为所有内容只会在类加载时加载。
从客户端的角度来看,静态行为是客户端已知的,但是Singleton行为可以在客户端隐藏的情况下完成。客户可能永远不会知道,他一次又一次地玩着一个实例。
在我写的一篇文章中,我描述了关于单例为什么比静态类好得多的观点:
我们可以创建单例类的对象并将其传递给方法。
Singleton类没有任何继承限制。
我们不能处理静态类的对象,但可以单例处理类。
JDK有单例和静态的示例,一方面java.lang.Math
是带有静态方法的最终类,另一方面java.lang.Runtime
是单例类。
单身人士的优势
如果您需要维护状态而不是单例模式比静态类更好,因为在静态类中维护状态会导致错误,尤其是在并发环境中,这可能导致竞争状况,而没有足够的同步并行修改多个线程。
如果Singleton类是一个沉重的对象,则可以将其延迟加载,但是静态类没有这种优势,并且总是急于加载。
使用单例,您可以使用继承和多态性来扩展基类,实现接口并提供不同的实现。
由于Java中的静态方法不能被覆盖,因此会导致不灵活。另一方面,您可以通过扩展它覆盖单例类中定义的方法。
静态类的缺点
静态类的优点
详细说明每个都太冗长,因此我只链接了一篇好文章- 您想了解的有关Singleton的全部信息
单个静态类实例(即,一个类的实例,恰好是一个静态或全局变量)与指向堆上该类实例的单个静态指针之间存在巨大差异:
当您的应用程序退出时,将调用静态类实例的析构函数。这意味着,如果您将该静态实例用作单例,则单例将停止正常工作。如果仍在运行使用该单例的代码(例如在其他线程中),则该代码很可能崩溃。
我脑子里的不同是实现面向对象的编程(Singleton / Prototype)或功能编程(静态)。
当我们最后要保留一个对象时,我们太关注单例模式创建的对象数。就像其他人已经说过的那样,它可以扩展,作为参数传递,但最重要的是它是全状态的。
另一方面,static用于实现功能编程。静态成员属于一个类。他们是无国籍的。
顺便说一句,您知道可以创建单例静态类:)
getInstance()
(尽管在大多数情况下这并不重要)。