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

Design patterns 静态类和单例模式之间的区别?,design-patterns,static,singleton,Design Patterns,Static,Singleton,静态类和单例模式之间存在什么真正的(即实际的)区别 两者都可以在不实例化的情况下调用,都只提供一个“实例”,并且都不是线程安全的。还有其他区别吗?单例是实例化的,只是只有一个实例被实例化过,因此单例中的单例 静态类只能由自身实例化。在singleton模式中,您可以将singleton创建为派生类型的实例,但不能使用静态类 快速示例: if( useD3D ) IRenderer::instance = new D3DRenderer else IRenderer::instan

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


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

单例是实例化的,只是只有一个实例被实例化过,因此单例中的单例


静态类只能由自身实例化。

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

快速示例:

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

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


单例和一堆静态方法之间的最大区别在于,单例可以实现接口(或者从有用的基类派生,尽管这在我的经验中不太常见),因此您可以像传递“另一个”实现一样传递单例。

真正的答案是Jon Skeet

singleton允许访问单个 已创建实例-该实例(或 而是对该实例的引用) 可以作为参数传递给其他 方法,并作为正常对照 反对

静态类只允许静态 方法


与静态类相比,单例模式有几个优点。首先,单例可以扩展类并实现接口,而静态类不能(它可以扩展类,但不继承它们的实例成员)。单例可以延迟或异步初始化,而静态类通常在首次加载时初始化,这会导致潜在的类装入器问题。然而,最重要的优点是,可以以多态方式处理单例,而不必强迫用户假定只有一个实例。

静态类是一个只有静态方法的类,更好的说法是“函数”。静态类中体现的设计风格纯粹是过程性的


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

单例只是一个普通的类,只是从客户机代码实例化了一次,而且是间接的。静态类未实例化。 据我所知,静态方法(静态类必须有静态方法)比非静态方法快

编辑:
FxCop性能规则说明: “不访问实例数据或调用实例方法的方法可以标记为静态(在VB中共享)。执行此操作后,编译器将向这些成员发出非虚拟调用站点,这将阻止在运行时对每个调用进行检查,以确保当前对象指针为非空。这可能会导致性能敏感代码获得可测量的性能增益。在某些情况下,无法访问当前对象实例表示错误不透明度问题。”

我不知道这是否也适用于静态类中的静态方法。

我不是一个伟大的OO理论家,但据我所知,我认为静态类与单例类相比唯一缺少的OO特性是多态性。 但是,如果您不需要它,使用静态类,您当然可以继承(不确定接口实现)以及数据和函数封装

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

编辑:
我现在实际上在想,另一个区别是,静态类在程序开始时被实例化,并贯穿于程序的整个生命周期,而单例在某个点被显式实例化,也可以被销毁


*或者它可能在第一次使用时被实例化,这取决于语言,我认为。

静态类不适用于任何需要状态的东西。它有助于将一系列函数放在一起,即
Math
(或项目中的
Utils
)。所以类名只是给了我们一个线索,我们可以在哪里找到函数,什么都没有

Singleton
是我最喜欢的模式,我用它在一个点上管理一些东西。它比静态类更灵活,并且可以维护它的状态。它可以实现接口、从其他类继承并允许继承

我在
静态
单例
之间选择的规则:

如果有一组函数应该放在一起,那么选择
static

任何其他需要单独访问某些资源的内容都可以实现为
单例

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

  • 延迟加载
  • 支持接口,因此可以提供单独的实现
  • 能够返回派生类型(作为懒散加载和接口实现的组合)

  • 在许多情况下,这两个实例没有实际的区别,特别是如果单例实例从未更改或更改非常缓慢,例如保持配置

    我想说的是,最大的区别是,单例仍然是一个普通的Javabean,而不是专门的纯静态Java类。正因为如此,单身在更多的情况下被接受;事实上,这是默认的Spring框架的实例化策略。消费者可能知道也可能不知道这是一个被传递的单例,他们只是把它当作一个普通的JavaBEA
    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();
        }
    }
    
    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;
        }
    }
    
    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();
        }
    
    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");
        }
    }