Как правило, есть два шаблона для использования редко необходимых объектов, которые дорого создавать. Первый шаблон использует фабрику, как предлагает Дэвид Фэйвр. Другой - с использованием прокси.
Прокси-сервер - с точки зрения дизайна - возможно, самое чистое решение, хотя для его реализации может потребоваться больше кода. Он самый чистый, потому что приложение может совершенно об этом не знать, потому что вам не нужен дополнительный интерфейс (как требует заводской подход).
Вот простой пример с некоторым интерфейсом и дорогой реализацией:
interface IAmAService
{
void DoSomething();
}
class ExpensiveImpl : IAmAService
{
private object x = [some expensive init];
void IAmAService.DoSomething() { }
}
Нет, вы можете реализовать прокси на основе этого интерфейса, который может задержать создание этой реализации:
class ServiceProxy : IAmAService
{
private readonly Func<IAmAService> factory;
private IAmAService instance;
public ServiceProxy(Func<IAmAService> factory)
{
this.factory = factory;
}
void IAmAService.DoSomething()
{
this.GetInstance().DoSomething();
}
private IAmAService GetInstance()
{
// TODO: Implement double-checked lock only a single
// instance may exist per ServiceProxy.
if (this.instance == null)
{
this.instance = this.factory();
}
return this.instance;
}
}
Этот прокси-класс принимает делегата фабрики в качестве зависимости, как описал Дэвид Фэйвр в своем ответе, но в этом случае приложение не должно зависеть от Func<IAmAService>
, а может просто зависеть от IAmAService
.
Теперь вместо введения ExpensiveImpl
вы можете добавить ServiceProxy
в другие случаи:
// Create the proxy
IAmAService service =
new ServiceProxy(() => new ExpensiveImpl());
// Inject it into whatever you wish, such as:
var customerService = new CustomerService(service);