Здравствуйте, IB, Вы писали:
IB>"главная проблема синглтона в том, что это первый паттерн описанный в GoF" (c) MaximVK. На него набрасываются и не замечают его недостатков, из коих:
Это не недостатки синглтона ни в коем случае, не надо воодить народ к заблуждение.
IB>1. Синглтон нарушает SRP (Single Responsibility Principle) — класс синглтона, помимо того чтобы выполнять свои непосредственные обязанности, занимается еще и контролированием количества своих экземпляров.
Это глупость, причём документально подтверждённая GoF. Действительно, в GoF синглтон описан как
class Singleton {
public:
static Singleton* Instance();
protected:
Singleton();
private:
static Singleton* _instance;
}
и в таком виде описанная тобой проблема существует. Однако, не стоит заниматься буквоедством, тем более там, где это нелепо выглядит. Пример из книжки всегда прост и передаёт лишь суть и никогда не является объектом для дословного копирования. Всякий нормальный программист отделяет задачу контроля количества копий и пишет нечто вроде
template<T>
class singleton
{
public:
static const T * get_instance();
private:
static T * _instance;
}
либо
class Singleton<T> where T: new
{
private static T _instance = default(T);
public static T Instance { get; }
}
// или даже
class Singleton<T> where T: new, ISingleton
{
private static T _instance = default(T);
public static T Instance { get; }
}
либо как-то ещё, смотря от языка.
IB>2. Глобальное состояние. Про вред глобальных переменных вроде бы уже все знают, но тут та же самая проблема. Когда мы получаем доступ к экземпляру класса, мы не знаем текущее состояние этого класса, и кто и когда его менял, и это состояние может быть вовсе не таким, как ожидается. Иными словами, корректность работы с синглтоном зависит от порядка обращений к нему, что вызывает неявную зависимость подсистем друг от друга и, как следствие, серьезно усложняет разработку.
Singleton это stateless объект. Всякая другая его реализация ошибочна. Я тебя тут вообще не понял. Ты сперва сделал синглотон statefull объектом, а потом начал рассказывать какой синглотон плохой. Но это не синглтон плохой, это ты плохой, что сделал его statefull. Не надо путать тёплое с мягким.
IB>3. Зависимость обычного класса от синглтона не видна в публичном контракте класса. Так как обычно экземпляр синглтона не передается в параметрах метода, а получается напрямую, через GetInstance(), то для выявления зависимости класса от синглтона надо залезть в тело каждого метода — просто просмотреть публичный контракт объекта недостаточно.
Опять таки, ты сперва делаешь неверное предположение, а потом исходя из него строишь какие-то домыслы о недостатках синглтона. Кто сказал что зависимость обычного класса от синглтона должна быть видна? Вот у меня DAL зависит от системы журналирования, но из внешнего интерфейса DAL это не видно. И что? Я не вижу тут абсолютно никакой проблемы, тем более не вижу проблемы в синглтоне через который ведётся журналирования. Такого рода зависимости видны в настройках проекта и этого боле чем достаточно.
IB>4. Наличие синглтона понижает тестируемость приложения в целом и классов, которые используют синглтон, в частности. Во-первых, вместо синглтона нельзя подпихнуть Mock-объект, а во-вторых, если синглтон имеет интерфейс для изменения своего состояния, то тесты начинают зависеть друг от друга.
Во-первых, подкинуть Mock объект запросто можно (смотри второй пример на C#), во-вторых наличие состояний у синглтона это зло, причём зло в мозгах программиста, а не в синглтоне.
IB>Говоря же проще — синглтон повышает связность, и все вышеперечисленное, в том или ином виде, есть следствие повышения связности.
Да вообще зависимость одних модулей от других повышает связность
IB>Естественно, можно акккуратненько пройти по граблям и использовать синглетон, но (цитата из доки к пикоконтейнеру) "Overuse makes for bad solutions. At the enterprise level, it makes for very very bad solutions"...
Граблей никаких нет, если есть элементарное понимание области применения синглтона.
IB>Наибольшая же опасность, как было сказано, подстерегает при попытке построить на основе сиглтонов всю архитектуру приложения, такому подходу существует масса замечательных альтернатив. Например, IoC контейнеры — там проблема контроля создания сервисов решается естественным образом, так как они, по сути, являются "фабриками на стероидах" =). Другой альтернативой являются Service Locator-ы, из известных вариантов этого подхода — паттерн IServiceProvider.
Объясни мне доступно чем
GetService(typeof(MyService))
принципиальное лучше чем
Singleton<MyService>.Instance
если у нас всего один сервис.
Аргументы за сервисы, которые ты приводишь, актуальны, когда есть потребность в Chain of Responsibility, но это совсем другая задача.