首页 文章

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

提问于
浏览
1555

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

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

30 回答

  • 2

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

    照顾业务记住,最重要的OO规则之一是对象对自己负责 . 这意味着关于类的生命周期的问题应该在类中处理,而不是委托给像static这样的语言结构,等等 .

    来自“面向对象的思想过程”第四版 .

  • 1

    主要区别是:

    • Singleton有一个实例/对象,而静态类是一堆静态方法

    • Singleton可以扩展,例如通过接口而静态类不能 .

    • Singleton可以继承,它支持SOLID原则中的开/关原则,另一方面静态类不能被继承,我们需要自己进行更改 .

    • Singleton对象可以传递给方法,而静态类因为它没有实例,所以不能作为参数传递

  • 23

    单例只是一个正常的类,它被实例化,但只是一次,间接来自客户端代码 . 静态类未实例化 . 据我所知,静态方法(静态类必须有静态方法)比非静态方法快 .

    编辑:
    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."
    我实际上并不知道这是否也适用于静态类中的静态方法 .

  • 14

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

    湾虽然我们已将构造函数设为私有,但静态成员变量仍将被传递给子类 .

    C . 我们不能进行延迟初始化,因为只有在加载类时才会加载所有内容 .

  • 1085

    从客户端的角度来看,客户端已知静态行为,但可以从客户端隐藏Singleton行为 . 客户可能永远不会知道他一次又一次地玩一个单一的实例 .

  • 1
    • 我们可以创建单例类的对象并将其传递给方法 .

    • Singleton类没有任何继承限制 .

    • 我们不能处理静态类的对象但可以单例类 .

  • 2

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

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

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

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

  • 32

    从测试角度看,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来模拟静态,但并非所有产品都可以使用它 .

  • 17
    • Singleton对象存储在 Heap 中,但静态对象存储在 stack 中 .

    • 我们可以 clone (如果设计者没有禁止它)单例对象,但是我们无法克隆静态类对象 .

    • Singleton类遵循 OOP (面向对象的原则),静态类不遵循 .

    • 我们可以用Singleton类实现 interface ,但是类的静态方法(或者例如C# static class )不能 .

  • 3

    这是一篇好文章:http://javarevisited.blogspot.com.au/2013/03/difference-between-singleton-pattern-vs-static-class-java.html

    静态类

    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");
        }
    }
    

    Singleton

    总之,我只使用静态类来保存util方法,并将Singleton用于其他所有方法 .


    Edits

  • 4

    single static class 实例(即,类的单个实例,恰好是静态或全局变量)与堆上类的实例的 single static pointer 之间存在巨大差异:

    当您的应用程序退出时,将调用静态类实例的析构函数 . 这意味着如果您将该静态实例用作单例,则单例停止正常工作 . 如果仍然运行使用该单例的代码,例如在不同的线程中,该代码可能会崩溃 .

  • 4

    我们的数据库框架与后端 Build 连接 . 为了避免对多个用户进行脏读,我们使用了单例模式来确保我们在任何时候都可以使用单个实例 .

    在c#中,静态类无法实现接口 . 当单个实例类需要为业务 Contract 或IoC目的实现接口时,这就是我使用Singleton模式而没有静态类的地方

    Singleton提供了一种在无状态场景中维护状态的方法

    希望对你有所帮助..

  • 423

    在许多情况下,这两者没有实际区别,特别是如果单例实例从未改变或变化非常缓慢,例如持有配置 .

    我说最大的区别是单例仍然是一个普通的Java Bean,而不是专门的静态Java类 . 因此,在更多情况下接受单身人士;它实际上是Spring Framework的默认实例化策略 . 消费者可能知道也可能不知道它是一个单例被传递,它只是像普通的Java bean一样对待它 . 如果需求变化和单身需要相反,正如我们在Spring中看到的那样,它可以完全无缝地完成,而无需对消费者进行一系列代码更改 .

    其他人之前已经提到静态类应该是纯粹的程序性的,例如java.lang.Math中 . 在我看来,这样的类永远不应该被传递,除了静态final之外,它们永远不应该作为属性 . 对于其他一切,使用单例,因为它更灵活,更易于维护 .

  • 5

    正如我理解静态类和非静态Singleton类之间的区别,静态只是C#中的非实例化“类型”,其中Singleton是一个真正的“对象” . 换句话说,静态类中的所有静态成员都被分配给该类型,但是在Singleton中被置于该对象下 . 但请记住,静态类仍然表现得像引用类型,因为它不是像Struct这样的值类型 .

    这意味着当你创建一个Singleton时,因为类本身不是静态的但是它的成员是,优点是Singleton中的静态成员引用它本身连接到一个实际的“对象”而不是它自身的空洞“类型” . 现在澄清了静态和非静态单例之间的区别,超出了它的其他功能和内存使用,这让我感到困惑 .

    两者都使用静态成员,它们是成员的单个副本,但是Singleton将引用的成员包装在真实例化的“对象”周围,除了静态成员之外,该对象还存在地址 . 该对象本身具有属性,其中in可以传递并引用,增加值 . Static类只是一个类型,因此除了指向其静态成员之外它不存在 . 这种概念巩固了Singleton vs Static Class的目的,超越了继承和其他问题 .

  • 5

    Singleton模式比静态类有几个优点 . 首先,单例可以扩展类和实现接口,而静态类不能(它可以扩展类,但不会继承它们的实例成员) . 单例可以懒惰或异步初始化,而静态类通常在首次加载时初始化,从而导致潜在的类加载器问题 . 然而,最重要的优点是单例可以多态处理,而不会强迫用户假设只有一个实例 .

  • 17

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

  • 21

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

    快速示例:

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

    为了说明如果Logger是静态类,则无法完成下面显示的Jon 's point what' . 类 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();
        }
    }
    
  • 2

    在我写的一篇文章中,我描述了我为什么单例比静态类好得多的观点:

    • 实际上并不是静态类规范类 - 它是具有函数和变量的命名空间

    • 由于违反了面向对象的编程原则,使用静态类不是一个好习惯

    • 静态类不能作为其他参数传递

    • 静态类不适合“延迟”初始化

    • 始终难以跟踪静态类的初始化和使用

    • 实现线程管理很难

  • 53

    我同意这个定义:

    单个“单词”表示应用程序生命周期中的单个对象,因此范围处于应用程序级别 . 静态没有任何Object指针,因此范围是App Domain级别 . 此外,两者都应该实现为线程安全的 .

    你可以找到有趣的其他差异:Singleton Pattern Versus Static Class

  • 1

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

    单例和一堆静态方法之间的最大区别在于单例可以实现接口(或者从有用的基类派生,尽管根据我的经验这不太常见),所以你可以传递单例,好像它只是“另一个” “实施 .

  • 8

    真正的答案是Jon Skeet,on another forum here .

    单例允许访问单个创建的实例 - 该实例(或者更确切地说,对该实例的引用)可以作为参数传递给其他方法,并视为普通对象 . 静态类只允许静态方法 .

  • 11

    static 类不应该做任何需要状态的事情,它有助于将一堆函数放在一起,即 Math (或项目中的 Utils ) . 因此, class 名称只是给我们一个线索,我们可以在哪里找到这些功能,而且仅此而已 .

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

    我在 staticsingleton 之间选择的规则:

    如果有一堆函数应该保存在一起,那么 static 就是选择 . 任何需要单独访问某些资源的东西都可以实现 singleton .

  • 4

    Singleton 's are instantiated, it' s只有一个实例被实例化,因此Singleton中的单个实例 .

    静态类不能由其他任何东西实例化 .

  • 2

    静态类是仅具有静态方法的类,对于该类,更好的单词将是“函数” . 静态类中体现的设计风格纯粹是程序性的 .

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

  • 336

    要扩展Jon Skeet's Answer

    单例和一堆静态方法之间的最大区别在于单例可以实现接口(或者从有用的基类派生,虽然这不太常见的IME),所以你可以传递单例,好像它只是“另一个”实现 .

    单元测试课程时,单身人士更容易使用 . 无论您将单例作为参数(构造函数,设置器或方法)传递,您都可以替换单例的模拟或存根版本 .

  • 0

    一个值得注意的差异是Singletons带来的不同实例化 .

    对于静态类,它由CLR创建,我们无法控制它 . 对于单例,对象在尝试访问的第一个实例上实例化 .

  • 128

    Static Class:-

    • 您无法创建静态类的实例 .

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

    • Static Class不能有构造函数 .

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

    • 我们不能将Static类继承到C#中的另一个Static类 .

    • 具有所有静态方法的类 .

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

    Singleton:-

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

    • Singleton实例是在用户请求时首次创建的 .

    • Singleton类可以有构造函数 .

    • 您可以创建singleton类的对象并将其传递给method .

    • Singleton类没有说继承的任何限制 .

    • 我们可以处理单例类的对象,但不能处理静态类的对象 .

    • 可以覆盖方法 .

    • 可以在需要时延迟加载(始终加载静态类) .

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

  • 48
    • 延迟加载

    • 支持接口,以便可以提供单独的实现

    • 能够返回派生类型(作为延迟加载和接口的组合实现)

  • 3

    当我想要具有完整功能的课程时,例如有很多方法和变量,我使用单例;

    如果我想要只有一种或两种方法的类,例如MailService类,它只有1个方法SendMail()我使用静态类和方法 .

相关问题