静态类和单例模式之间存在什么真实(即实际)差异?
两者都可以在没有实例化的情况下调用,两者都只提供一个"实例",它们都不是线程安全的.还有其他区别吗?
是什么让你说单例或静态方法不是线程安全的?通常两者都应该实现为线程安全的.
单例和一堆静态方法之间的最大区别在于单例可以实现接口(或者从有用的基类派生,尽管根据我的经验这不太常见),所以你可以传递单例,好像它只是"另一个" "实施.
真正的答案是Jon Skeet,在另一个论坛上.
单例允许访问单个创建的实例 - 该实例(或者更确切地说,对该实例的引用)可以作为参数传递给其他方法,并作为普通对象处理.
静态类只允许静态方法.
Singleton对象存储在Heap中,但静态对象存储在堆栈中.
我们可以克隆(如果设计者不允许它)单例对象,但是我们不能克隆静态类对象.
Singleton类遵循OOP(面向对象的原则),而静态类则不遵循.
我们可以interface
使用Singleton类来实现,但是类的静态方法(或者例如C#static class
)不能.
Singleton模式比静态类有几个优点.首先,单例可以扩展类和实现接口,而静态类不能(它可以扩展类,但不会继承它们的实例成员).单例可以懒惰或异步初始化,而静态类通常在首次加载时初始化,从而导致潜在的类加载器问题.然而,最重要的优点是单例可以多态处理,而不会强迫用户假设只有一个实例.
static
类不应该做任何需要状态的东西,它可以将一堆函数放在一起,即Math
(或Utils
在项目中).因此,班级名称只是给我们一个线索,我们可以在哪里找到这些函数,仅此而已.
Singleton
是我最喜欢的模式,并使用它来管理单点的东西.它比static
类更灵活,可以维持状态.它可以实现接口,从其他类继承并允许继承.
我对之间进行选择的规则static
和singleton
:
如果有一堆功能应该保持在一起,那么static
就是选择.可以实现任何其他需要单独访问某些资源的东西singleton
.
静态类: -
您无法创建静态类的实例.
加载包含类的程序或命名空间时,由.NET Framework公共语言运行库(CLR)自动加载.
静态类不能有构造函数.
我们无法将静态类传递给方法.
我们不能将Static类继承到C#中的另一个Static类.
具有所有静态方法的类.
更好的性能(静态方法在编译时绑定)
辛格尔顿: -
您可以创建该对象的一个实例并重用它.
Singleton实例是在用户请求时首次创建的.
Singleton类可以有构造函数.
您可以创建singleton类的对象并将其传递给method.
Singleton类没有说继承的任何限制.
我们可以处理单例类的对象而不是静态类的对象.
方法可以被覆盖.
可以在需要时加载延迟(始终加载静态类).
我们可以实现接口(静态类不能实现接口).
静态类是仅具有静态方法的类,对于该类,更好的单词将是"函数".静态类中体现的设计风格纯粹是程序性的.
另一方面,Singleton是OO设计特有的模式.它是一个对象的实例(具有其中固有的所有可能性,例如多态性),具有创建过程,该过程确保在其整个生命周期中只有该特定角色的一个实例.
在单例模式中,您可以将单例创建为派生类型的实例,但不能使用静态类.
快速示例:
if( useD3D ) IRenderer::instance = new D3DRenderer else IRenderer::instance = new OpenGLRenderer
扩展Jon Skeet的答案
单例和一组静态方法之间的最大区别在于单例可以实现接口(或者从有用的基类派生,尽管这不常见于IME),因此您可以传递单例,就好像它只是"另一个"实现一样.
单元测试课程时,单身人士更容易使用.无论您将单例作为参数(构造函数,设置器或方法)传递,您都可以替换单例的模拟或存根版本.
这是一篇很好的文章: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"); } }
一个只能实例化一次的对象.
方法可以被覆盖(为什么Java不允许覆盖静态方法?)
更容易模拟静态方法
更好地保持国家
总之,我只使用静态类来保存util方法,并将Singleton用于其他所有方法.
编辑
静态类也是延迟加载的.谢谢@jmoreno(静态类初始化何时发生?)
隐藏静态类的方法.谢谢@MaxPeng.
单例的另一个优点是它可以轻松地序列化,如果您需要将其状态保存到光盘或远程发送到某个地方,这可能是必要的.
我不是一个伟大的OO理论家,但据我所知,我认为静态类与Singletons相比缺乏的唯一OO特性是多态性.但是如果你不需要它,使用静态类,你当然可以继承(不确定接口实现)和数据和函数封装.
Morendil的评论,"静态类中体现的设计风格纯粹是程序性的"我可能错了,但我不同意.在静态方法中,您可以访问静态成员,这与访问其单个实例成员的单例方法完全相同.
编辑:
我现在实际上在想,另一个区别是静态类在程序启动时被实例化*并且在程序的整个生命周期中存在,而单例在某个时刻被显式实例化并且也可以被销毁.
*或者它可能会在第一次使用时被实例化,具体取决于语言,我认为.
为了说明Jon的观点,如果Logger是一个静态类,则无法完成下面显示的内容.该类SomeClass
需要将ILogger
实现的实例传递给它的构造函数.
Singleton类对于依赖注入是很重要的.
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(); } }
单例只是一个正常的类,它被实例化,但只是一次,间接来自客户端代码.静态类未实例化.据我所知,静态方法(静态类必须有静态方法)比非静态方法快.
编辑:
FxCop性能规则描述:"不访问实例数据或调用实例方法的方法可以标记为静态(在VB中共享).执行此操作后,编译器将向这些成员发出非虚拟调用站点,这将阻止在运行时检查确保当前对象指针为非空的每个调用.这可以为性能敏感的代码带来可测量的性能提升.在某些情况下,访问当前对象实例的失败代表了正确性问题.
我实际上并不知道这是否也适用于静态类中的静态方法.
Singleton是实例化的,只有一个实例被实例化,因此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()是很困难的.您可以使用power mock来模拟静态,但并非所有产品都可以使用它.
我同意这个定义:
" 单个 " 一词在整个应用程序生命周期中表示单个对象,因此范围在应用程序级别.
该静没有任何对象的指针,因此范围是在应用程序域级别.
此外,两者都应该实现为线程安全的.
您可以找到有趣的其他差异:Singleton Pattern与Static Class
主要区别是:
Singleton有一个实例/对象,而静态类是一堆静态方法
Singleton可以通过接口扩展,而静态类不能扩展.
Singleton可以继承,它支持SOLID原则中的开/关原则,另一方面静态类不能被继承,我们需要自己进行更改.
Singleton对象可以传递给方法,而静态类因为它没有实例不能作为参数传递
一个值得注意的差异是Singletons带来的不同实例化.
对于静态类,它由CLR创建,我们无法控制它.对于单例,对象在尝试访问的第一个实例上实例化.