2013-04-24 3 views
5

У меня есть точка в моем дизайне, где я серьезно рассматриваю синглтон.Возможно ли использование Singleton?

Как мы все знаем, «общим» аргументом является «Никогда не делай этого! Это ужасно!», Как будто мы засорили наш код кучей goto заявлений.

ServiceStack прекрасная инфраструктура. Я и моя команда продаются на нем, и у нас есть сложная инфраструктура, основанная на веб-сервисах. Я ободряю асинхронный дизайн и, где это возможно, используя SendAsync на клиентах службы-стека.

Учитывая, что у нас есть все эти разные системы, которые делают разные вещи, мне пришло в голову, что я хотел бы иметь общий регистратор (сам веб-сервис на самом деле, с возвратом к локальному текстовому файлу, если веб-сайт сервис недоступен - например, некоторые демоны преследуют здание). Хотя я большой поклонник Injection Dependency Injection, мне кажется не чистым (по крайней мере, мне) передавать ссылку на «использование этого клиента-регистратора» на каждый асинхронный запрос.

Учитывая, что сигнатура сбоя ServiceStack - это Func<TRESPONSE, Exception> (и у меня нет с этим никаких проблем), я даже не уверен, что если метод включения, который сделал вызов в первую очередь, имел бы действительный дескриптор.

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

Является ли это признанным действительным случаем, или это не аргумент - с одиночными точками?

+0

«Как мы все знаем,« общим »аргументом является« Никогда не делайте этого! Это ужасно! »« Обычное где? – Filip

+0

Я почти никогда не использую статические классы, и я избегаю синглтона, но я не считаю их такими же ужасными, и я не хочу, чтобы мой код зависел от них. – eandersson

+1

@Filip, вам не придется много искать в Google или StackOverflow, чтобы найти «гнев бригады Anti-Singleton». Хотя есть и те, кто считает, что он всегда будет иметь свое место в некоторых нишевых сценариях, есть и те, кто откажется от голосования, если он использует синглтон как пример *. Поэтому я решил, что лучше всего задать вопрос в интересах лучшей практики. И вот для чего этот сайт для :) –

ответ

3

Регистрация является одной из областей, которая имеет смысл быть синглом, она не должна иметь никаких побочных эффектов для вашего кода, и вы почти всегда хотите, чтобы один и тот же регистратор использовался в глобальном масштабе. Основное, с чем вам следует иметь отношение при использовании Singletons, - ThreadSafety, который, в случае большинства Loggers, по умолчанию является ThreadSafe.

ServiceStack's Logging API позволяет одновременно обеспечить замещаемый Logging реализацию путем настройки глобально на App_Start с:

LogManager.LogFactory = new Log4NetFactory(configureLog4Net:true); 

После этого момента каждый класс теперь имеет доступ к регистратору Log4Net, определяемого в Фабрике выше:

class Any 
{ 
    static ILog log = LogManager.GetLogger(typeof(Any)); 
} 

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

LogManager.LogFactory = new ConsoleLogFactory(); 

По умолчанию ServiceStack.Logging, регистрируется в доброкачественном NullLogger, который игнорирует каждую запись в журнале.

+0

Это вроде того, как мой разум работал. Я не вижу проблемы с использованием сингла здесь (и поверьте мне, я стараюсь их избегать). Для простоты простоты и того, что вы начертили выше, хорошо - почему бы и нет? –

0

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

Есть еще две проблемы, которые могут возникнуть у вас. На вопрос, который у меня для вас есть: вы уверены, что не слишком много входите в журнал, и уверены, что не нарушаете принципы SOLID.

Я написал SO answer a year back that discusses those two questions. Я советую вам прочитать его.

+0

Спасибо за ваш ответ, Стивен. Существующая инфраструктура * делает слишком много логарифмов, но это не мое беспокойство - это инфраструктура «продвижения вперед». Я - большой поклонник регистрации * при необходимости *. В нашем бизнесе много внутренних и сторонних систем, и, хотя мои предшественники, возможно, были чрезмерно усердны в «Log it!». (очевидно, с различными реализациями .. wtf?), мне нужна более чистая стратегия «Log when you need to». –

0

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

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

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

3

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

по классической реализации я имею в виду это:

class Singleton 
{ 
    public static readonly Singleton Instance = new Singleton(); 
    private Singleton(){} 
    public void Foo(){} 
    public void Bar(){} 
} 

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

+0

И вот где мой ум на момент написания. У него будет единственный метод. 'Log (запись LogEntry)'. Остальное - это нечто большее. Нам не нужно регистрировать все, что мы делаем. Нам нужно зайти в журнал, когда что-то случилось, что требует внимания, или мы хотим, чтобы какой-то показатель производительности (могут быть и другие случаи ...). Я не вижу, что «интерфейс» регистратора меняется со временем. Это «эй, запишите это где-нибудь, пожалуйста», а затем перейдите. –

+1

Итак, что вас беспокоит? Вы не хотите вводить один интерфейс ILogger в каждый запрос по соображениям производительности? Накладные расходы памяти не являются проблемой, так как логгер будет одиночным.Что касается изменения логического интерфейса - вы всегда можете расширить его за счетчиком, поддерживая интерфейс. Реализация может регистрировать показатели производительности, записывать в файлы, db, отправлять электронные письма и т. Д. Также не забывайте о тестировании, как сказал @Steven в своем ответе. Если вы используете прямую ссылку на регистратор - вам придется инициализировать или каким-то образом издеваться над этим в своих тестах. – Alexander

Смежные вопросы