Pull to refresh

Comments 17

не пойму, зачем прятать «синглтоновость»? ведь если система грамотно спроэктирована, то менять его не потребуется, потому что у меня уже всё расписано, кто за что отвечает и если я поменяю что-либо, то я нарушу систему. не знаю, это конечно мое мнение, лично я еще не сталкивался с таким.
Singleton'овость нужно прятать по той же причине, по которой нужно прятать любые другие детали реализации. Систему рано или поздно приходится менять под новые, постоянно меняющиеся требования.
Кстати, модифицируемость – это один из архитектурных атрибутов качества. Т.е. грамотно спроектированная система должна позволять вносить изменения в компоненты, не нарушая целостность системы.
Это у Вас пройдет :) К сожалению, даже большие и известные компании временами (или большую часть времени) работают по принципу «мы тут поменяли одну маленькую деталь в тз», при котором изначального проектирования тупо хватает на одну-две итерации. Можно сказать, что это нормальный подход для бизнеса — мы выпустили фичу, посмотрели, внесли коррекцию; можно говорить, что это дурь менеджеров, которые не знают чего хотят, но факт остается фактом — Ваш подход здесь работать не будет.
Вернее есть один тонкий момент — он будет помогать, если Вы изначально, при старте системы, продумывали именно интерфейсы, чтобы сделать их максимально гибкими и независимыми от реализации того, что внутри, и чтобы можно было как можно чаще уже придуманными интерфейсами снабжать новые компоненты. На костях же темного прошлого светлое будущее построить не удастся.
>> А что если возникнет необходимость реализовать класс по-другому?
Это как? Разные инстансы, если они между собой отличаются, можно создавать, передавая конфиг или тип инстанса в getInstance(). Если же такой тип уже существует, то можно либо отдавать уже готовый объект, либо создавать такой же (или даже клонировать готовый и сбрасывать в исходное состояние).
У нас когда-то была обратная ситуация — при переходе на mod_perl было замечено, что несколько классов было бы здорово превратить в синглтоны. Естественно, никому в голову не пришло менять метод new по всему коду на getInstance, так new и оставили. И надо сказать, это оказалось весьма практичным и красивым решением. Сейчас приходится работать с наследниками Class::Singleton, и от вызовов метода instance возникает некоторый диссонанс. Думаю, это подсознательное предчувствие подставы в виде возможного изменения интерфейса или логики поведения.
Да, обратная ситуация тоже может произойти, просто это более редкий случай. IoCC помогает и в обратной ситуации тоже.
Выдаем еще один аргумент в вашу пользу.
Я его не раз озвучивал нашим упертым идеогам, которые мою концепцию не приняли. Или не поняли.
Суть проста.
Если ВСЕГДА при операции с обьектов требуется писать getInstance — это значит что ее ВСЕГДА можно не писать.
Просто реализовав утверждение «что ты один» в самом обьекте, а по сути врезав «префикс вызова» в сам обьект.

Либо обернув обычный синглентон в интерфейс-врапер, либо просто расшарив свойства по всем экземплярам обьекта.

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

Пример Cache->getInstance(namespace) — позволяет получить несколько различных синглтонов различных вариантов кеша.
Удобно, логично, никаких нарушений стандартов.
А вот какойнить SESSION — должен выдавать различные свои варианты в зависимости от вызывателя, при этом оставался с виду обычным сингтоном.
SESSION == Session->getInstance(CurrentClient->sessionInstance), на С\С++ можно через дефайн завернуть, на других языках — через враперы или интерфейсы.
Но опять же — если что-то пишеться всегда, значит его никогда не надо писать. И надо убирать с глаз долой.
А вы бы написали примерчик, как IoC скрывать «синглтоновость».
Примерчик получился бы очень и очень тривиальный. Примерно такой:

@Singleton
public class MyService implements IMyService
{
   // ...
}
Ах да, в Джаве же есть эти инструкции с собачкой (название из головы вылетело =\). А обращение к нему идет всегда через контейнер?
Обращение будет таким:

public class YourClass
{
   @Inject
   IMyService myService;
   // ...
}

YourClass не знает о том, что реализация IMyService помечена как @Singleton, поэтому мы можем эту аннотацию убирать/добавлять в любой момент.
И переменную myService даже не нужно инициализировать что ли? И ведь обычно синглтон — объект, доступный всем, его не делают полем.
Да, переменную myService инициализировать руками не нужно, её проинициализирует IoC контейнер в соответствии с аннотациями, которые стоят над IMyService и MyService.

Да, Singleton в определении GoF, содержит фразу: «… и предоставляет к нему глобальную точку доступа...», но IoCC освобождает Singleton от этой обязанности, что позволяет «Синглетоновость» делать деталью реализации а не частью интерфейса. Моя статья именно об этом.
У GoF Singleton не делают полем, потому что «синглтоновость» – это часть интерфейса класса.

В IoCC YourClass не знает о том, будет IMyService синглтоном или нет, «синглтоновость» спрятана как деталь реализации, поэтому под каждый синглтон надо заводить поле, и поэтому первоначальное решение о том, что MyService должен быть синглтоном можно отменить в любой момент.
Sign up to leave a comment.

Articles