Разница между статическим классом и одноэлементным шаблоном?

Какая реальная (т.е. практическая) разница между статическим классом и одноэлементным шаблоном?

Оба могут быть вызваны без экземпляра, оба предоставляют только один экземпляр, и ни один из них не является потокобезопасным. Есть ли другая разница?

+1638
06 февр. '09 в 8:13
источник поделиться
39 ответов
  • 1
  • 2

Что заставляет вас говорить, что либо одноэлементный, либо статический метод не является потокобезопасным? Обычно оба должны быть реализованы для обеспечения безопасности потоков.

Большая разница между одноэлементным и пучком статических методов заключается в том, что синглтоны могут реализовывать интерфейсы (или извлекать из полезных базовых классов, хотя это и не так часто, по моему опыту), поэтому вы можете проходить вокруг синглтона, как если бы это было "просто еще одна" реализация.

+1149
06 февр. '09 в 8:17
источник

Истинный ответ: Jon Skeet, на другом форуме здесь.

Синглтон позволяет получить доступ к одному созданный экземпляр - этот экземпляр (или скорее, ссылка на этот экземпляр) может передаваться как параметр в другой методы и рассматриваются как нормальные объект.

Статический класс допускает только статический Методы.

+439
06 февр. '09 в 8:21
источник
  • Объекты Singleton хранятся в Куче, но статические объекты хранятся в стеке.
  • Мы можем clone (если дизайнер не запретил его) одиночный объект, но мы не можем клонировать объект статического класса .
  • Одиночные классы следуют ООП (объектно-ориентированные принципы), статические классы этого не делают.
  • Мы можем реализовать interface с классом Singleton, но статические методы класса (или, например, С# static class) не могут.
+342
11 сент. '12 в 10:22
источник

Шаблон Singleton имеет несколько преимуществ перед статическими классами. Во-первых, singleton может расширять классы и реализовывать интерфейсы, а статический класс не может (он может расширять классы, но не наследует их экземпляры). Синтаксис может быть инициализирован лениво или асинхронно, в то время как статический класс обычно инициализируется при его первой загрузке, что приводит к потенциальным проблемам загрузчика класса. Однако самым важным преимуществом является то, что синглтоны могут обрабатываться полиморфно, не заставляя своих пользователей предполагать, что существует только один экземпляр.

+136
06 февр. '09 в 8:30
источник

static классы не для чего-либо, что нуждается в состоянии. Это полезно для объединения нескольких функций, например, Math (или Utils в проектах). Таким образом, имя класса просто дает нам подсказку, где мы можем найти функции и ничего более.

Singleton - мой любимый шаблон, и я использую его для управления чем-то в одной точке. Он более гибкий, чем static классы, и может поддерживать его состояние. Он может реализовывать интерфейсы, наследовать от других классов и разрешать наследование.

Мое правило выбора между static и singleton:

Если есть несколько функций, которые должны храниться вместе, тогда static выбор. Все остальное, для которого требуется единый доступ к некоторым ресурсам, может быть реализовано как единое singleton.

+62
30 дек. '10 в 20:55
источник

Статический класс: -

  • Вы не можете создать экземпляр статического класса.

  • Загружается автоматически средой общего языка .NET Framework (CLR), когда загружается программа или пространство имен, содержащее класс.

  • Статический класс не может иметь конструктор.

  • Мы не можем передать статический класс методу.

  • Мы не можем наследовать класс Static другому классу Static в С#.

  • Класс, имеющий все статические методы.

  • Лучшая производительность (статические методы связаны во время компиляции)

Singleton: -

  • Вы можете создать один экземпляр объекта и повторно использовать его.

  • Экземпляр Singleton создается в первый раз, когда пользователь запрашивал.

  • Класс Singleton может иметь конструктор.

  • Вы можете создать объект класса singleton и передать его методу.

  • В классе Singleton не существует ограничений наследования.

  • Мы можем уничтожить объекты одноэлементного класса, но не статического класса.

  • Методы могут быть переопределены.

  • Может быть ленив загружаться, когда это необходимо (статические классы всегда загружаются).

  • Мы можем реализовать интерфейс (статический класс не может реализовать интерфейс).

+55
01 июн. '15 в 11:42
источник

Статический класс - это тот, который имеет только статические методы, для которых лучшим словом будет "функции". Стиль дизайна, воплощенный в статическом классе, является чисто процедурным.

Синглтон, с другой стороны, является шаблоном, специфичным для дизайна OO. Это экземпляр объекта (со всеми возможностями, присущими этому, например, полиморфизм), с процедурой создания, которая гарантирует, что на протяжении всего жизненного цикла есть только один экземпляр этой конкретной роли.

+49
06 февр. '09 в 8:35
источник

В одиночном шаблоне вы можете создать singleton как экземпляр производного типа, вы не можете сделать это со статическим классом.

Быстрый пример:

if( useD3D )
    IRenderer::instance = new D3DRenderer
else
    IRenderer::instance = new OpenGLRenderer
+33
06 февр. '09 в 8:16
источник

Чтобы перейти на Jon Skeet Answer

Большая разница между одноэлементным и пустым статическими методами заключается в том, что синглеты могут реализовывать интерфейсы (или извлекать из полезных базовых классов, хотя это менее распространенный IME), поэтому вы можете обойти синглтон, как если бы это было "просто другое".

Синглтоны легче работать при модульном тестировании класса. Где бы вы ни проходили одиночные игры в качестве параметра (конструкторы, сеттеры или методы), вы можете вместо этого заменить издеваемую или оштукатуренную версию синглтона.

+24
20 дек. '12 в 21:53
источник

Еще одно преимущество singleton состоит в том, что его можно легко сериализовать, что может потребоваться, если вам нужно сохранить его состояние на диск или отправить его удаленно.

+21
08 авг. '11 в 3:36
источник

Вот хорошая статья: 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");
        }
    }
    

одиночка

Таким образом, я бы использовал статические классы только для хранения утилит, а для всего остального - синглтон.


Правки

+19
24 апр. '14 в 1:22
источник

Я не большой теоретик ОО, но из того, что знаю, я думаю, что единственная функция OO, которая не имеет статических классов по сравнению с Singletons, - это полиморфизм. Но если вам это не нужно, со статическим классом вы, конечно, можете иметь наследование (не уверен в реализации интерфейса) и инкапсуляцию данных и функций.

Комментарий Морендила: "Стиль дизайна, воплощенный в статическом классе, чисто процедурный", я могу ошибаться, но я не согласен. В статических методах вы можете получить доступ к статическим членам, которые будут точно такими же, как singleton-методы, доступ к их отдельным членам экземпляра.

Редактирование:
Я сейчас думаю, что другое отличие состоит в том, что класс Static создается при запуске программы * и живет на протяжении всей жизни программы, в то время как синглтон явно создается в какой-то момент и может быть уничтожен.

* или он может быть создан при первом использовании, в зависимости от языка, я думаю.

+17
16 авг. '09 в 15:54
источник

Чтобы проиллюстрировать точку Джона, то, что показано ниже, не может быть выполнено, если 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();
    }
}
+15
09 июн. '13 в 23:49
источник

Ну, одноэлемент - это просто нормальный класс, созданный IS, но только один раз и косвенно из клиентского кода. Статический класс не создается. Насколько я знаю, статические методы (статический класс должен иметь статические методы) быстрее, чем нестатические.

Edit:
Описание правила производительности FxCop: "Методы, которые не имеют доступа к данным экземпляра или вызовам экземпляров, могут быть помечены как статические (Shared in VB). После этого компилятор будет выдавать не виртуальные сайты вызовов этим членам, что предотвратит проверку во время выполнения для каждого вызова, который заставляет текущий указатель объекта не пустым. Это может привести к измеримому усилению производительности для кода, чувствительного к производительности. В некоторых случаях отказ в доступе к экземпляру текущего объекта представляет собой проблему корректности".
Я действительно не знаю, относится ли это также к статическим методам в статических классах.

+11
06 февр. '09 в 9:36
источник

Синтаксис создается, он только один экземпляр, когда-либо созданный, поэтому сингл в Singleton.

Статический класс не может быть создан каким-либо другим, чем он сам.

+9
06 февр. '09 в 8:15
источник

Синглтон лучше подходит для тестирования. В отличие от статических классов, singleton может реализовывать интерфейсы, и вы можете использовать mock instance и вставлять их.

В приведенном ниже примере я проиллюстрирую это. Предположим, что у вас есть метод isGoodPrice(), который использует метод getPrice(), и вы реализуете getPrice() как метод в singleton.

singleton, обеспечивающий функциональность 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(). Вы можете издеваться над статикой с манерой власти, но не все ее могут использовать.

+6
13 апр. '14 в 12:55
источник

Я согласен с этим определением:

Слово " одиночный " означает один объект в жизненном цикле приложения, поэтому область действия находится на уровне приложения.

Статика не имеет указателя объекта, поэтому область действия находится на уровне домена приложения.

Более того, оба должны быть реализованы, чтобы быть потокобезопасными.

Вы можете найти интересные другие отличия о: шаблон Singleton и статический класс

+6
11 февр. '16 в 15:08
источник

Основные отличия:

  • Синглтон имеет экземпляр/объект, а статический класс - это куча статических методов
  • Singleton может быть расширен, например, через интерфейс, в то время как статический класс не может быть.
  • Синглтон может быть унаследован, который поддерживает принципы open/close в принципах SOLID, с другой стороны, статический класс не может быть унаследован, и мы должны сами вносить изменения.
  • Объект Singleton может быть передан методам, тогда как статический класс, поскольку он не имеет экземпляра, не может быть передан как параметры
+6
28 апр. '18 в 16:12
источник

Одна заметная разница - это различное инстанцирование, которое приходит с синглтонами.

Со статическими классами он создается CLR, и мы не контролируем его. с синглтонами, объект получает экземпляр в первом экземпляре, к которому он пытался получить доступ.

+5
27 июн. '12 в 14:03
источник

У нас есть наша инфраструктура DB, которая делает подключения к Back end. Чтобы избежать грязных чтений в нескольких пользователей, мы использовали шаблон singleton, чтобы обеспечить доступность одного экземпляра в любой момент времени.

В С# статический класс не может реализовать интерфейс. Когда одному экземпляру класса необходимо реализовать интерфейс для бизнес-контрактов или целей IoC, здесь я использую шаблон Singleton без статического класса

Singleton обеспечивает способ сохранения состояния в сценариях без учета состояния

Надеюсь, что поможет вам.

+4
27 июн. '12 в 9:58
источник

Во многих случаях эти два не имеют практической разницы, особенно если экземпляр singleton никогда не изменяется или изменяется очень медленно, например. поддерживающих конфигурации.

Я бы сказал, что самая большая разница в том, что синглтон по-прежнему является нормальным Java Bean, поскольку он противоположен специализированному статическому классу Java. И из-за этого синглтон принимается во многих других ситуациях; это фактически стандартная стратегия создания Spring Framework. Потребитель может или не может знать, что один элемент передается, он просто рассматривает его как обычную Java bean. Если требование изменяется, и одноэлемент должен стать прототипом вместо этого, как мы часто видим в Spring, это можно сделать полностью без изменений, если бы строка кода не изменилась бы на потребителя.

Кто-то еще упомянул ранее, что статический класс должен быть чисто процедурным, например. java.lang.Math. На мой взгляд, такой класс никогда не должен быть передан, и они никогда не должны содержать ничего, кроме статического окончательного в качестве атрибутов. Для всего остального используйте синглтон, поскольку он намного более гибкий и более простой в обслуживании.

+4
07 июн. '12 в 1:07
источник
  • Мы можем создать объект класса singleton и передать его методу.

  • Класс Singleton не имеет никакого ограничения наследования.

  • Мы не можем уничтожить объекты статического класса, но можем использовать одноэлементный класс.

+3
18 окт. '16 в 18:58
источник
  • В С# статический класс не может реализовать интерфейс. Когда один класс экземпляра должен реализовать интерфейс для некоторых бизнес-процессов причины или цели IoC, вы можете использовать шаблон Singleton без статический класс.
  • Вы можете клонировать объект Singleton, но вы не можете клонировать статический объект класса
  • Одиночные объекты хранятся в куче, но статические объекты хранятся в стеке
  • Синтаксис может быть инициализирован лениво или асинхронно, в то время как статический класс обычно инициализируется при первой загрузке
+3
19 июн. '16 в 3:14
источник
  • Lazy Loading
  • Поддержка интерфейсов, так что может быть предоставлена ​​отдельная реализация
  • Возможность возврата производного типа (как комбинация lazyloading и реализации интерфейса)
+3
08 мая '12 в 16:34
источник

Я читаю следующее и думаю, что это тоже имеет смысл:

Уход за бизнесом

Помните, что одним из наиболее важных правил OO является то, что объект отвечает за себя. Это означает, что вопросы, касающиеся жизненного цикла класса, должны обрабатываться в классе, а не делегироваться языковым конструкциям, таким как статические, и т.д.

из книги "Объектно-ориентированный процесс мышления" 4-е изд.

+3
30 дек. '15 в 21:05
источник

В статье, которую я написал, я описал свою точку зрения о том, почему синглтон намного лучше, чем статический класс:

  • Статический класс не является фактически каноническим классом - его пространство имен с функциями и переменными
  • Использование статического класса не является хорошей практикой из-за нарушения принципов объектно-ориентированного программирования.
  • Статический класс нельзя передать как параметр для других
  • Статический класс не подходит для "ленивой" инициализации
  • Инициализация и использование статического класса всегда трудно отслеживаются
  • Реализация управления потоками сложна.
+3
13 нояб. '13 в 10:56
источник

С точки зрения клиента статическое поведение известно клиенту, но поведение Singleton может быть скрыто от клиента. Клиент может никогда не знать, что есть только один экземпляр, в котором он играет снова и снова.

+3
04 авг. '14 в 6:23
источник

а. Сериализация - статические члены относятся к классу и, следовательно, не могут быть сериализованы.

б. Хотя мы сделали частный конструктор, статические переменные-члены все еще будут перенесены в подкласс.

с. Мы не можем выполнять ленивую инициализацию, поскольку все будет загружаться только при загрузке класса.

+3
14 янв. '14 в 17:46
источник

Существует огромная разница между экземпляром одиночного статического класса (то есть единственным экземпляром класса, который является статической или глобальной переменной) и одиночным статическим указателем к экземпляру класса в куче:

Когда ваше приложение выйдет, вызывается деструктор экземпляра статического класса. Это означает, что если вы использовали этот статический экземпляр как одноэлементный, ваш синглтон перестает работать должным образом. Если есть еще работающий код, который использует этот синглтон, например, в другом потоке, этот код может сбой.

+2
31 мар. '14 в 13:33
источник

Когда мне нужен класс с полной функциональностью, например. существует много методов и переменных, я использую singleton;

Если я хочу, чтобы класс содержал только один или два метода, например. Класс MailService, который имеет только 1 метод SendMail() Я использую статический класс и метод.

+1
27 мая '12 в 22:42
источник
  • 1
  • 2

Посмотрите другие вопросы по меткам или Задайте вопрос