Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
if(instance != null) return instance; считывают null и переходят к инструкции Singleton temp = new Singleton();Почему нехорошо «обманывать» язык? Потому что каждый такой «хак» очень легко нечаянно поломать. И потому что от него нет никакой пользы людям, которые пишут на других языках — а ведь паттерн предполагает универсальность.
public static class Singleton, при использовании C#, хуже всего вышеописанного?Модульные тесты являются практически стандартной инженерной практикой. При написании тестов Синглтоны оказываются проблемой. Заменить mock'ом без модификации его практически не возможно.
Вторая неприятность с Синглтоном — он делает зависимости неочевидными. Глядя на интерфейс класса, невозможно узнать увидеть все его зависимости. Для этого нужно смотреть реализацию медодов.
Проблема, которую он решает Синглтон — это убедиться, что в системе существует один, и только один экземпляр ресурса. В подовляющем большинстве случаев эту проблему можно решить другим способом — используя Dependency Injection.
Вероятно, вы хотите протестировать класс, зависящий от синглтона. Но эта постановка задачи неверна — класс должен зависеть от абстракции, а не от конкретной реализации (иначе бы никакие замены были невозможно, и мы бы не говорили о модульном тестировании). Следовательно, то, что вы тестируете, должно рассчитывать на получение экземпляра определенной абстракции (интерфейса, класса — не такАбсолютно верно.
важно), и, в принципе, даже не обязано знать о том, сколько этих экземпляров в системе.
Следующий вопрос — откуда этот экземпляр взять, и вот он к синглтону как паттерну отношения не имеет.
Эта проблема вообще не имеет отношения к синглтону. Это типичная проблема любых неявных зависимостей (статических фабрик, сервис-локаторов и так далее). Соответственно, вам просто нужно выбрать (общий для всего проекта) стиль передачи/получения зависимостей (и у явного, и у неявного есть свои достоинства и недостатки) и придерживаться его.
Разделяйте dependency management и instance/construction/lifetime management. Мы можем взять DI как парадигму и Unity как IoC-контейнер, реализовать DI через вбрасывание в конструктор, а для конкретной зависимости указать, что ее Lifetime manager — ContainerControlled. Получим синглтон в DI — потому что у класса есть ровно один экземпляр. Можем сделать все то же самое, но выбрать не DI, а ServiceLocation (например, потому, что у нас нет контроля за созданием объектов) — получим синглтон через локатор (визуально практически не отличающийся от обычного синглтона).Абсолютно верно.
Синглтон предлагает изолировать его и предоставить один метод для доступа к ресурсу, скажем MyResource.getInstance().
В книге «Working effectively with legacy code» предлагается сделать лазейку в виде сеттера MyResource.setInstance(). Но тогда есть опасность что этот метод будет использован кроме тестов еще и в продакшн коде.
Вместо в место Синглтонов и статических фабрик предпочтительнее использовать DI.
На стадии конструирования у нас есть полный контроль на тем сколько экземпляров мы создали, и в использовании Синглтона нет необходимости.
Способ решения — «Сделайте класс Синглтон, который который контроллирует создание экземпляра и предоставляет доступ к этому экземпляра»
In general, a pattern has four essential elements:
- The pattern name is a handle we can use to describe a design problem, its solutions, and consequences in a word or two.....
- The problem describes when to apply the pattern......
- The solution describes the elements that make up the design, their relationships, responsibilities, and collaborations. The solution doesn't describe a particular concrete design or implementation, because a pattern is like a template that can be applied in many different situations. Instead, the pattern provides an abstract description of a design problem and how a general arrangement of elements (classes and objects in our case) solves it.
- The consequences are the results and trade-offs of applying the pattern.....
Participants
- Singleton
- defines an Instance operation that lets clients access its unique instance. Instance is a class operation (that is, a class method in Smalltalk and a static member function in C++).
- may be responsible for creating its own unique instance.
А вот это как раз неверно. На стадии конструирования нам надо определить, сколько экземпляров мы создали, и если для какого-то класса мы создаем один экземпляр, то это и есть паттерн Singleton.
if(instance != null) return instance;
Monitor.Enter(s_lock);
Singleton temp = new Singleton();
Interlocked.CompareExchange(ref instance, temp, null);
Monitor.Exit(s_lock);
return instance;
// If the Singleton was already created, just return it (this is fast)
if (s_value != null) return s_value;
Monitor.Enter(s_lock); // Not created, let 1 thread create it
if (s_value == null) {
// Still not created, create it
Singleton temp = new Singleton();
// Save the reference in s_value (see discussion for details)
Interlocked.Exchange(ref s_value, temp);
}
Monitor.Exit(s_lock);
// Return a reference to the one Singleton object
return s_value;
if (s_value != null) return s_value;
// Create a new Singleton and root it if another thread didn't do it first
Singleton temp = new Singleton();
Interlocked.CompareExchange(ref s_value, temp, null);
// If this thread lost, then the second Singleton object gets GC'd
return s_value; // Return reference to the single object
Три возраста паттерна Singleton