Итак, я провел много исследований по этому поводу и не нашел ответов, где бы я сказал «да, ЭТО». Я надеюсь, что эрудированная толпа StackOverflow сможет мне помочь.
Я столкнулся с этой проблемой в нескольких разных сценариях. Скажем, у меня есть приложение C#, и есть важные вещи, которые я хочу регистрировать.
public class MyClass
{
...
public void ImportantMethod()
{
DoInterestingThing();
var result = SomethingElseImportant();
if (result == null)
{
logger.Log("I wasn't expecting that. No biggie.");
return;
}
MoreInterestingStuff();
}
Меня интересует откуда взять logger
.
Как я вижу, у меня есть несколько вариантов.
- Внедрите его в MyClass в конструкторе.
- Получите его, используя глобально доступный локатор сервисов.
- Используйте декораторы методов и АОП, чтобы ведение журнала выполнялось за меня.
Ни один из этих вариантов не кажется отличным. # 3 выглядит невозможным, поскольку я веду регистрацию прямо в середине своей бизнес-логики, а не просто выполняю простую трассировку вызовов моих методов, входных параметров и/или исключений. # 2, хотя просто кажется, что было бы очень сложно провести модульное тестирование. Конечно, я бы хотел протестировать все. № 1, хотя он и работал бы нормально, загромождает всю мою бизнес-логику объектами протоколирования, которые не имеют ничего общего с самими бизнес-объектами.
Любые альтернативные идеи или мысли по одному из вариантов выше? Большое спасибо!
РЕДАКТИРОВАТЬ: просто для ясности, я уже знаю, как делать DI (я использую Unity), и я уже знаю хорошую структуру ведения журнала (я использую log4net). Просто интересно, как использовать ведение журнала в архитектурном смысле в приложении самым разумным образом.
* ИЗМЕНИТЬ *
Я отметил ответ Марка Симана как решение. Я просмотрел свое приложение и обнаружил, что большинство моих вызовов ведения журнала делают то же самое, что и декоратор. А именно, запишите запись в метод, любые выброшенные исключения и возвращаемые значения выхода.
В некоторых случаях мне по-прежнему нужно было вести журнал непосредственно внутри метода. Примером может быть то, что я хочу быстро потерпеть неудачу в методе, который ничего не возвращает, но не throw Исключение. В этих случаях у меня есть синглтон, который содержит ссылку LogProvider
, которая, в свою очередь, извлечет именованный экземпляр журнала. Код выглядит примерно так:
private ILog logger = LogProviderFactory.Instance.GetLogger(typeof(Foo));
LogProviderFactory имеет метод SetProvider
, который позволяет вам заменить синглтон. Итак, в модульном тестировании я могу сделать:
// LogProviderFactory.Instance now is our mock
LogProviderFactory.SetProvider(MockLogProvider);
Декоратор ведения журнала использует тот же LogProvider, что и синглтон (который он получает путем внедрения), поэтому ведение журнала унифицировано во всей системе.
Так что на самом деле конечным решением был в основном вариант № 3 и гибрид № 2 (где это шаблон локатора службы, но служба «внедряется» в локатор).
АОП
Что касается «аспектно-ориентированного программирования», то я был немного разочарован ограничениями языка. Надеемся, что в будущих выпусках к АОП будут относиться как к первоклассному гражданину.
- Я попробовал PostSharp, но не смог правильно запустить его на своей машине. Кроме того, было большим ограничением, что вам нужно было установить PostSharp в вашей системе, чтобы использовать его (в отличие от простого вызова dll, который поставляется с решением или чем-то подобным).
- Я использовал LinFu и смог частично заставить его работать. Однако в нескольких случаях он взрывался. Новая версия 2.0 почти не документирована, так что это было препятствием.
- Однако перехват интерфейса с Unity, кажется, работает хорошо из коробки. Мне повезло, что большинство вещей, которые я хотел регистрировать, находились в классах, реализующих интерфейсы.