Стоит ли перехват накладных расходов, которые он создает?
Я нахожусь в процессе значительных усилий по внедрению NHibernate в нашу кодовую базу. Я подумал, что мне придется использовать какой-то DI-контейнер, чтобы я мог внедрить зависимости в сущности, которые я загружаю из базы данных. Я выбрал Unity в качестве этого контейнера.
Я рассматриваю возможность использования механизма перехвата Unity для добавления аспекта транзакции в мой код, чтобы я мог, например, сделать следующее:
class SomeService
{
[Transaction]
public void DoSomething(CustomerId id)
{
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
}
}
и [Transaction]
Обработчик позаботится о создании сеанса и транзакции, фиксации транзакции (или откате исключения) и т. д.
Я обеспокоен тем, что использование такого вида перехвата свяжет меня с использованием Unity практически везде в коде. Если я представлю аспекты таким образом, то никогда не буду называть new SomeService()
Или я получу сервис, в котором нет транзакций. Хотя это приемлемо в производственном коде, в тестах это кажется слишком сложным. Например, я должен был бы преобразовать это:
void TestMethod()
{
MockDependency dependency = new MockDependency();
dependency.SetupForTest();
var service = SomeService(dependency);
service.DoSomething();
}
в это:
void TestMethod()
{
unityContainer.RegisterType<MockDependency>();
unityContainer.RegisterType<IDependency, MockDependency>();
MockDependency dependency = unityContainer.Resolve<MockDependency>();
dependency.SetupForTest();
var service = unityContainer.Resolve<SomeService>();
service.DoSomething();
}
Это добавляет 2 строки для каждого фиктивного объекта, который я использую, что приводит к небольшому количеству кода (наши тесты используют много имитаций с состоянием, поэтому в тестовом классе не редкость иметь 5-8 фиктивных объектов, и иногда больше.)
Я не думаю, что автономное внедрение могло бы помочь в этом: мне нужно настроить внедрение для каждого класса, который я использую в тестах, потому что возможно добавление аспектов в класс после написания теста.
Теперь, если я откажусь от использования перехвата, я получу:
class SomeService
{
public void DoSomething(CustomerId id)
{
Transaction.Run(
() => {
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
});
}
}
что, по общему признанию, не так хорошо, но тоже не так уж и плохо.
Я даже могу настроить собственный перехват бедняков:
class SomeService
{
[Transaction]
public void DoSomething(CustomerId id)
{
Interceptor.Intercept(
MethodInfo.GetCurrentMethod(),
() => {
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
});
}
}
и тогда мой перехватчик может обработать атрибуты для класса, но я все еще могу создать экземпляр класса, используя new
и не беспокоиться о потере функциональности.
Есть ли лучший способ использования перехвата Unity, который не заставляет меня всегда использовать его для создания экземпляров моих объектов?
1 ответ
Если вы хотите использовать AOP, но заинтересованы в Unity, я бы порекомендовал вам попробовать PostSharp. Это реализует AOP как проверку после компиляции, но не имеет изменений в том, как вы используете код во время выполнения.
У них есть бесплатная версия сообщества с хорошим набором функций, а также профессиональные и корпоративные версии, в которых значительно улучшены наборы функций.