design patterns whisky 静态类和单例模式之间的区别?




singleton是什么 (24)

单身人士只是一个普通的类,它被实例化,但只是一次和间接地从客户端代码。 静态类没有实例化。 据我所知静态方法(静态类必须有静态方法)比非静态方法更快。

编辑:
FxCop性能规则描述:“不访问实例数据或调用实例方法的方法可以被标记为静态的(在VB中共享),这样做后,编译器会向这些成员发出非虚拟调用位置,这将阻止在运行时确保当前对象指针是非空的,这可能会导致性能敏感代码的性能提升,在某些情况下,无法访问当前对象实例代表正确性问题。
我实际上不知道这是否也适用于静态类中的静态方法。

静态类和单例模式之间存在什么真正的(即实际的)区别?

两者都可以在没有实例化的情况下被调用,它们都只提供一个“实例”,而且它们都不是线程安全的。 还有其他的区别吗?


真正的答案是Jon Skeet, 在这里的另一个论坛上

单例允许访问单个创建的实例 - 该实例(或者对该实例的引用)可以作为参数传递给其他方法,并作为普通对象处理。

静态类只允许静态方法。


  • 在c#中,一个静态类不能实现一个接口。 当一个实例类需要为了一些商业原因或IoC目的而实现接口时,可以使用Singleton模式而不使用静态类。
  • 您可以克隆Singleton的对象,但不能克隆静态类对象
  • Singleton对象存储在堆中,但静态对象存储在堆栈中
  • 单例可以初始化为懒惰或异步,而静态类通常在首次加载时初始化

  1. 延迟加载
  2. 支持接口,以便可以提供单独的实现
  3. 能够返回派生类型(作为延迟加载和接口实现的组合)

单例的另一个优点是它可以很容易地被序列化,如果你需要将它的状态保存到光盘或者将它发送到远程的地方,这可能是必要的。


  1. We can create the object of singleton class and pass it to method.

  2. Singleton class doesn't any restriction of inheritance.

  3. We can't dispose the objects of a static class but can singleton class.


When I want class with full functionality, eg there are many methods and variables, I use singleton;

If I want class with only one or two methods in it, eg MailService class, which has only 1 method SendMail() I use static class and method.


是什么让你说单线程或静态方法不是线程安全的? 通常两者都应该被实现为线程安全的。

单身人士和一些静态方法之间的巨大差异是单身人士可以实现接口(或者从有用的基类派生,尽管这在我的经验中不太常见),所以你可以绕过单身人士,就好像它是“另一个“实施。


在很多情况下,这两者没有实际区别,特别是如果单例实例永远不会改变或缓慢变化,例如持有配置。

我认为最大的区别是单身仍然是一个普通的Java Bean,与专门的静态Java类相反。 正因为如此,单身人士在更多情况下被接受。 它实际上是默认的Spring Framework的实例化策略。 消费者可能会或可能不知道它是一个单身人士,它只是把它当作普通的Java bean来对待。 如果需求发生变化,而单例需要成为原型,就像我们在Spring中经常看到的那样,它可以完全无缝地完成,而不需要为消费者修改代码。

其他人之前提到,静态类应该是纯粹的过程化的,比如java.lang.Math。 在我看来,这样的一个类永远不应该被传递,他们绝不应该把静态final作为属性。 对于其他任何事情,使用单例,因为它更加灵活和易于维护。


从客户端的角度来看,客户端已知静态行为,但单身人士行为可以从客户端隐藏完成。 客户可能永远不会知道他只有一次他一次又一次地玩弄。


我不是一个很棒的OO理论家,但从我所知道的,我认为静态类与Singleton相比缺乏的唯一OO特性是多态性。 但是如果你不需要它,用一个静态类你当然可以继承(不确定接口实现)和数据和函数封装。

Morendil的评论,“静态类中体现的设计风格纯粹是程序性的”我可能是错的,但我不同意。 在静态方法中,您可以访问静态成员,这与访问其单个实例成员的单例方法完全相同。

编辑:
我现在实际上在想,另一个区别是,一个Static类在程序启动时实例化并且贯穿程序的整个生命周期,而一个单例在某个时刻被显式实例化,并且也可以被销毁。

*或者可能会在初次使用时实例化,具体取决于语言,我认为。


一个静态类只有静态方法,对此,一个更好的词将是“功能”。 体现在静态类中的设计风格纯粹是程序性的。

另一方面,Singleton是面向对象设计的特定模式。 它是一个对象的实例(具有内在的所有可能性,例如多态性),创建过程确保在整个生命周期中只有一个特定角色的实例。


static类不应该做任何需要状态的事情,将一些函数放在一起即Math (或项目中的Utils )是非常有用的。 所以班级名称只是给我们一个线索,我们可以找到功能,没有什么更多。

Singleton是我最喜欢的模式,并用它来管理单点事物。 它比static类更灵活,并且可以保持状态。 它可以实现接口,从其他类继承并允许继承。

我的选择staticsingleton规则:

如果有一堆功能应该放在一起,那么static是选择。 任何需要单一访问某些资源的其他内容都可以通过singleton实现。


这里有一篇很好的文章: http://javarevisited.blogspot.com.au/2013/03/difference-between-singleton-pattern-vs-static-class-java.html : 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来完成其他任何事情。

编辑


一个。 序列化 - 静态成员属于该类,因此无法序列化。

湾 尽管我们已经将构造函数设置为私有,但静态成员变量仍将被传递给子类。

C。 我们不能做懒惰的初始化,因为所有的东西都只会在类加载时加载。


我阅读以下内容并认为它也很有意义:

照顾生意

请记住,最重要的面向对象规则之一是对象负责自身。 这意味着有关类生命周期的问题应该在类中处理,而不是委托给静态等语言结构。

从“面向对象的思想过程”第4版。


  1. 单例对象存储在堆中 ,但静态对象存储在堆栈中
  2. 我们可以克隆 (如果设计者不禁止它)单例对象,但我们不能克隆静态类对象。
  3. 单例类遵循OOP (面向对象原则),静态类不遵守。
  4. 我们可以用Singleton类实现一个interface ,但是类的静态方法(或者C# static class )不能。

为了说明Jon的观点,如果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中只有一个实例。

一个静态类不能被其他任何东西实例化。


There is a huge difference between a single static class instance (that is, a single instance of a class, which happens to be a static or global variable) and a single static pointer to an instance of the class on the heap:

When your application exits, the destructor of the static class instance will be called. That means if you used that static instance as a singleton, your singleton ceased working properly. If there is still code running that uses that singleton, for example in a different thread, that code is likely to crash.


在单例模式中,您可以将单例创建为派生类型的实例,但不能使用静态类来完成。

快速示例:

if( useD3D )
    IRenderer::instance = new D3DRenderer
else
    IRenderer::instance = new OpenGLRenderer

扩展Jon Skeet的答案

单例和一堆静态方法之间的巨大差异是单例可以实现接口(或者从有用的基类派生,尽管这不是常见的IME),所以你可以将单例传递给它,就好像它是“另一个”实现一样。

单元测试课程时单身人士更容易使用。 无论您将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()就很困难。 你可以用动力模拟来嘲弄静态,但并非所有的产品都可以使用它。


静态类: -

  1. 您不能创建静态类的实例。

  2. 当加载包含类的程序或名称空间时,由.NET Framework公共语言运行库(CLR)自动加载。

  3. 静态类不能有构造函数。

  4. 我们无法将静态类传递给方法。

  5. 我们不能将静态类继承到C#中的另一个静态类。

  6. 一个拥有所有静态方法的类。

  7. 更好的性能(静态方法在编译时绑定)

辛格尔顿: -

  1. 您可以创建对象的一个​​实例并重用它。

  2. 当用户请求时,第一次创建单例实例。

  3. Singleton类可以有构造函数。

  4. 您可以创建单例类的对象并将其传递给方法。

  5. Singleton类不会说任何继承的限制。

  6. 我们可以处理单个类的对象,但不能处理静态类的对象。

  7. 方法可以被覆盖。

  8. 需要时可以延迟加载(静态类总是加载)。

  9. 我们可以实现接口(静态类不能实现接口)。





singleton