编辑: FxCop性能规则说明:"Methods which do not access instance data or call instance methods can be marked as static (Shared in VB). After doing so, the compiler will emit non-virtual call sites to these members which will prevent a check at runtime for each call that insures the current object pointer is non-null. This can result in a measurable performance gain for performance-sensitive code. In some cases, the failure to access the current object instance represents a correctness issue." 我实际上并不知道这是否也适用于静态类中的静态方法 .
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);
}
}
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");
}
}
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();
}
}
30 回答
我读了以下内容并认为它也有意义:
来自“面向对象的思想过程”第四版 .
主要区别是:
Singleton有一个实例/对象,而静态类是一堆静态方法
Singleton可以扩展,例如通过接口而静态类不能 .
Singleton可以继承,它支持SOLID原则中的开/关原则,另一方面静态类不能被继承,我们需要自己进行更改 .
Singleton对象可以传递给方法,而静态类因为它没有实例,所以不能作为参数传递
单例只是一个正常的类,它被实例化,但只是一次,间接来自客户端代码 . 静态类未实例化 . 据我所知,静态方法(静态类必须有静态方法)比非静态方法快 .
编辑:
FxCop性能规则说明:"Methods which do not access instance data or call instance methods can be marked as static (Shared in VB). After doing so, the compiler will emit non-virtual call sites to these members which will prevent a check at runtime for each call that insures the current object pointer is non-null. This can result in a measurable performance gain for performance-sensitive code. In some cases, the failure to access the current object instance represents a correctness issue."
我实际上并不知道这是否也适用于静态类中的静态方法 .
一个 . 序列化 - 静态成员属于该类,因此无法序列化 .
湾虽然我们已将构造函数设为私有,但静态成员变量仍将被传递给子类 .
C . 我们不能进行延迟初始化,因为只有在加载类时才会加载所有内容 .
从客户端的角度来看,客户端已知静态行为,但可以从客户端隐藏Singleton行为 . 客户可能永远不会知道他一次又一次地玩一个单一的实例 .
我们可以创建单例类的对象并将其传递给方法 .
Singleton类没有任何继承限制 .
我们不能处理静态类的对象但可以单例类 .
我不是一个伟大的OO理论家,但据我所知,我认为静态类与Singletons相比缺乏的唯一OO特性是多态性 . 但是如果你不需要它,使用静态类,你当然可以继承(不确定接口实现)和数据和函数封装 .
Morendil的评论,“静态类中体现的设计风格纯粹是程序性的”我可能错了,但我不同意 . 在静态方法中,您可以访问静态成员,这与访问其单个实例成员的单例方法完全相同 .
编辑:
我现在实际上在想,另一个区别是静态类在程序启动时实例化*并且在程序的整个生命周期中存在,而单例在某个时刻被显式实例化并且也可以被销毁 .
*或者它可能会在第一次使用时被实例化,具体取决于语言,我认为 .
从测试角度看,Singleton是更好的方法 . 与静态类不同,单例可以实现接口,您可以使用模拟实例并注入它们 .
在下面的例子中,我将说明这一点 . 假设您有一个方法isGoodPrice(),它使用方法getPrice()并将getPrice()实现为单例中的方法 .
提供getPrice功能的单例:
使用getPrice:
最终的Singleton实现:
考试类:
如果我们采用静态方法来实现getPrice()的替代方法,那么模拟getPrice()很难 . 您可以使用power mock来模拟静态,但并非所有产品都可以使用它 .
Singleton对象存储在 Heap 中,但静态对象存储在 stack 中 .
我们可以 clone (如果设计者没有禁止它)单例对象,但是我们无法克隆静态类对象 .
Singleton类遵循 OOP (面向对象的原则),静态类不遵循 .
我们可以用Singleton类实现
interface
,但是类的静态方法(或者例如C#static class
)不能 .这是一篇好文章:http://javarevisited.blogspot.com.au/2013/03/difference-between-singleton-pattern-vs-static-class-java.html
静态类
一个全部 static methods 的类 .
性能更好(静态方法在编译时绑定)
不能覆盖方法,但可以使用方法隐藏 . (What is method hiding in Java? Even the JavaDoc explanation is confusing)
Singleton
an object 只能实例化一次 .
方法可以被覆盖(Why doesn't Java allow overriding of static methods?)
更容易模拟然后静态方法
更好地保持国家
总之,我只使用静态类来保存util方法,并将Singleton用于其他所有方法 .
Edits
静态类也是延迟加载的 . 谢谢@jmoreno(When does static class initialization happen?)
方法隐藏静态类 . 谢谢@MaxPeng .
single static class 实例(即,类的单个实例,恰好是静态或全局变量)与堆上类的实例的 single static pointer 之间存在巨大差异:
当您的应用程序退出时,将调用静态类实例的析构函数 . 这意味着如果您将该静态实例用作单例,则单例停止正常工作 . 如果仍然运行使用该单例的代码,例如在不同的线程中,该代码可能会崩溃 .
我们的数据库框架与后端 Build 连接 . 为了避免对多个用户进行脏读,我们使用了单例模式来确保我们在任何时候都可以使用单个实例 .
在c#中,静态类无法实现接口 . 当单个实例类需要为业务 Contract 或IoC目的实现接口时,这就是我使用Singleton模式而没有静态类的地方
Singleton提供了一种在无状态场景中维护状态的方法
希望对你有所帮助..
在许多情况下,这两者没有实际区别,特别是如果单例实例从未改变或变化非常缓慢,例如持有配置 .
我说最大的区别是单例仍然是一个普通的Java Bean,而不是专门的静态Java类 . 因此,在更多情况下接受单身人士;它实际上是Spring Framework的默认实例化策略 . 消费者可能知道也可能不知道它是一个单例被传递,它只是像普通的Java bean一样对待它 . 如果需求变化和单身需要相反,正如我们在Spring中看到的那样,它可以完全无缝地完成,而无需对消费者进行一系列代码更改 .
其他人之前已经提到静态类应该是纯粹的程序性的,例如java.lang.Math中 . 在我看来,这样的类永远不应该被传递,除了静态final之外,它们永远不应该作为属性 . 对于其他一切,使用单例,因为它更灵活,更易于维护 .
正如我理解静态类和非静态Singleton类之间的区别,静态只是C#中的非实例化“类型”,其中Singleton是一个真正的“对象” . 换句话说,静态类中的所有静态成员都被分配给该类型,但是在Singleton中被置于该对象下 . 但请记住,静态类仍然表现得像引用类型,因为它不是像Struct这样的值类型 .
这意味着当你创建一个Singleton时,因为类本身不是静态的但是它的成员是,优点是Singleton中的静态成员引用它本身连接到一个实际的“对象”而不是它自身的空洞“类型” . 现在澄清了静态和非静态单例之间的区别,超出了它的其他功能和内存使用,这让我感到困惑 .
两者都使用静态成员,它们是成员的单个副本,但是Singleton将引用的成员包装在真实例化的“对象”周围,除了静态成员之外,该对象还存在地址 . 该对象本身具有属性,其中in可以传递并引用,增加值 . Static类只是一个类型,因此除了指向其静态成员之外它不存在 . 这种概念巩固了Singleton vs Static Class的目的,超越了继承和其他问题 .
Singleton模式比静态类有几个优点 . 首先,单例可以扩展类和实现接口,而静态类不能(它可以扩展类,但不会继承它们的实例成员) . 单例可以懒惰或异步初始化,而静态类通常在首次加载时初始化,从而导致潜在的类加载器问题 . 然而,最重要的优点是单例可以多态处理,而不会强迫用户假设只有一个实例 .
单例的另一个优点是它可以很容易地序列化,如果你需要将其状态保存到光盘或远程发送它,这可能是必要的 .
在单例模式中,您可以将单例创建为派生类型的实例,但不能使用静态类 .
快速示例:
为了说明如果Logger是静态类,则无法完成下面显示的Jon 's point what' . 类
SomeClass
期望将ILogger
实现的实例传递到其构造函数中 .单例类对于依赖注入是很重要的 .
在我写的一篇文章中,我描述了我为什么单例比静态类好得多的观点:
实际上并不是静态类规范类 - 它是具有函数和变量的命名空间
由于违反了面向对象的编程原则,使用静态类不是一个好习惯
静态类不能作为其他参数传递
静态类不适合“延迟”初始化
始终难以跟踪静态类的初始化和使用
实现线程管理很难
我同意这个定义:
你可以找到有趣的其他差异:Singleton Pattern Versus Static Class
是什么让你说单例或静态方法不是线程安全的?通常两者都应该实现为线程安全的 .
单例和一堆静态方法之间的最大区别在于单例可以实现接口(或者从有用的基类派生,尽管根据我的经验这不太常见),所以你可以传递单例,好像它只是“另一个” “实施 .
真正的答案是Jon Skeet,on another forum here .
static
类不应该做任何需要状态的事情,它有助于将一堆函数放在一起,即Math
(或项目中的Utils
) . 因此, class 名称只是给我们一个线索,我们可以在哪里找到这些功能,而且仅此而已 .Singleton
是我最喜欢的模式,用它来管理单点的东西 . 它比static
类更灵活,可以维持状态 . 它可以实现接口,从其他类继承并允许继承 .我在
static
和singleton
之间选择的规则:如果有一堆函数应该保存在一起,那么
static
就是选择 . 任何需要单独访问某些资源的东西都可以实现singleton
.Singleton 's are instantiated, it' s只有一个实例被实例化,因此Singleton中的单个实例 .
静态类不能由其他任何东西实例化 .
静态类是仅具有静态方法的类,对于该类,更好的单词将是“函数” . 静态类中体现的设计风格纯粹是程序性的 .
另一方面,Singleton是OO设计特有的模式 . 它是一个对象的实例(具有其中固有的所有可能性,例如多态性),具有创建过程,该过程确保在其整个生命周期中只有该特定角色的一个实例 .
要扩展Jon Skeet's Answer
单元测试课程时,单身人士更容易使用 . 无论您将单例作为参数(构造函数,设置器或方法)传递,您都可以替换单例的模拟或存根版本 .
一个值得注意的差异是Singletons带来的不同实例化 .
对于静态类,它由CLR创建,我们无法控制它 . 对于单例,对象在尝试访问的第一个实例上实例化 .
Static Class:-
您无法创建静态类的实例 .
加载包含类的程序或命名空间时,.NET Framework公共语言运行库(CLR)自动加载 .
Static Class不能有构造函数 .
我们无法将静态类传递给方法 .
我们不能将Static类继承到C#中的另一个Static类 .
具有所有静态方法的类 .
更好的性能(静态方法在编译时绑定)
Singleton:-
您可以创建对象的一个实例并重用它 .
Singleton实例是在用户请求时首次创建的 .
Singleton类可以有构造函数 .
您可以创建singleton类的对象并将其传递给method .
Singleton类没有说继承的任何限制 .
我们可以处理单例类的对象,但不能处理静态类的对象 .
可以覆盖方法 .
可以在需要时延迟加载(始终加载静态类) .
我们可以实现接口(静态类不能实现接口) .
延迟加载
支持接口,以便可以提供单独的实现
能够返回派生类型(作为延迟加载和接口的组合实现)
当我想要具有完整功能的课程时,例如有很多方法和变量,我使用单例;
如果我想要只有一种或两种方法的类,例如MailService类,它只有1个方法SendMail()我使用静态类和方法 .