Насколько быстро создается экземпляр класса с помощью методов, но без полей или свойств?
Вообще, создание экземпляров классов с методами, но без полей или свойств, имеет много накладных расходов?
Я занимаюсь разработкой приложения ASP.NET MVC, которое интенсивно использует инжекцию конструктора, и некоторые контроллеры имеют до 10 зависимостей. Но из-за большого количества зависимостей я прибег к IMyAppServiceProvider
интерфейс и класс, который обеспечивает общий доступ ко всем зависимостям через DependencyResolver в MVC 3.
Я вырвал весь свой специфический для приложения код и создал Gist с моей базовой настройкой (хотя она не включает установку BaseController, упомянутую ниже).
Я также создал класс BaseController, который принимает IMyAppServiceProvider
, Все контроллеры наследуются от этого базового класса. Базовый класс принимает IMyAppServiceProvider
объект и имеет защищенные переменные для всех различных служб. Код выглядит примерно так:
public class BaseController
{
protected IService1 _service1;
protected IService2 _service2;
protected IService3 _service3;
// ...
public BaseController(IMyAppServiceProvider serviceProvider)
{
_service1 = serviceProvider.GetService<IService1>;
_service2 = serviceProvider.GetService<IService2>;
_service3 = serviceProvider.GetService<IService3>;
// ...
}
}
Это делает код для контроллеров "скрипучим". Нет закрытых / защищенных переменных, нет присваиваний в конструкторе, и службы ссылаются на защищенные переменные базового класса. Однако каждый запрос будет создавать экземпляр каждой службы, которую использует мое приложение, вне зависимости от того, использует ли конкретный контроллер их все.
Мои сервисы просты и содержат вызовы методов с некоторой бизнес-логикой и взаимодействием с базой данных. Они не имеют состояния и не имеют полей или свойств класса. Следовательно, создание экземпляров должно быть быстрым, но мне интересно, является ли это наилучшей практикой (я знаю, что это загруженный термин).
2 ответа
каждый запрос будет создавать экземпляр каждой отдельной службы, которую использует мое приложение, независимо от того, использует ли конкретный контроллер их все.
Я полагаю, что вы сами ответили на свой вопрос, это не очень хороший подход. Более того, использование такого рода разрешения зависимостей (внедрение сервисного локатора) является плохой практикой, поскольку API контроллера становится грязным. Клиенты контроллера не знают, какие службы действительно необходимы для конкретного контроллера, поэтому вы можете столкнуться с неожиданными ошибками во время выполнения, модульное тестирование также будет беспорядочным.
Кстати, еще одно предложение - пометить все классы, которые считаются базовым классом, abstract
ключевое слово, таким образом, вы можете избежать использования его в качестве конкретного класса. Разработка и реализация базового класса - это конкретное проектное решение, поэтому проясните свои замыслы.
Что касается затрат на создание экземпляров, то в вашем случае это не будет иметь большого значения, но в целом, чтобы снизить затраты на создание экземпляров тяжелых объектов, вы можете:
- Используйте шаблон Prototype, чтобы "избежать внутренних затрат на создание нового объекта стандартным способом (например, с использованием ключевого слова" new "), когда это слишком дорого для данного приложения" (c) Википедия
- Используйте Lazy Initialization для сервисов, которые не нужны с начала времени жизни объекта-владельца, поэтому они будут инициализироваться по требованию. Поскольку.NET Framework 4.0 может использовать встроенный класс Lazy(T)
Я думаю, что решение, которое вы ищете здесь, заключается в использовании собственной фабрики контроллеров. Таким образом, каждый созданный контроллер имеет именно те зависимости, которые ему нужны. Вот один для StructureMap, из weblogs.asp.net:
using StructureMap;
public class StructureMapControllerFactory : DefaultControllerFactory {
protected override IController GetControllerInstance(Type controllerType) {
try {
return ObjectFactory.GetInstance(controllerType) as Controller;
}
catch (StructureMapException) {
System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());
throw;
}
}
}
protected void Application_Start() {
RegisterRoutes(RouteTable.Routes);
//Configure StructureMapConfiguration
// TODO: config structuremap
//Set current Controller factory as StructureMapControllerFactory
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
}