У меня есть интерфейс (назовите его IAcmeService), который имеет несколько реализаций.
FileSystemAcmeService
DatabaseAcmeService
NetworkAcmeService
Конечный пользователь должен быть в состоянии выбрать, какая реализация будет использоваться и также сохранит тот выбор.
В настоящее время я настраиваю свой контейнер IOC (Единица) для регистрации всего известного implemenatation в имени.
container.RegisterType(of IAcmeService, FileSystemAcmeService)("FileSystemAcmeService")
container.RegisterType(of IAcmeService, DatabaseAcmeService)("DatabaseAcmeService")
container.RegisterType(of IAcmeService, NetworkAcmeService)("NetworkAcmeService")
Чтобы позволить пользователю сохранять их выбор, у меня есть app.config файл раздела конфигурации, который хранит выбранное сервисное название к использованию.
Для разрешения выбранной реализации, я выполняю в ручной Твердости Инициализировать метод класса использование сервис.
Private _service as IAcmeService
Public Sub Initialize()
_service = container.Resolve(of IAcmeService)(_config.AcmeServiceName)
End Sub
Это не кажется правильным, потому что мой класс должен знать о контейнере. Но я не могу выяснить иначе.
Там другие пути состоят в том, чтобы позволить выбор конечного пользователя без класса, знающего о контейнере?
Определение и реализация и Абстрактная фабрика - это стандартное решение этого типа проблемы. Если вы простите мое использование C #, вы можете определить интерфейс IacmeserviceFactoractoractoractoractory, такой как это:
public interface IAcmeServiceFactory
{
IAcmeService Create(string serviceName);
}
Теперь вы можете написать конкретное внедрение, подобное этому:
public class AcmeServiceFactory : IAcmeServiceFactory
{
private readonly IAcmeService fsService;
private readonly IAcmeService dbService;
private readonly IAcmeService nwService;
public AcmeServiceFactory(IAcmeService fsService,
IAcmeService dbService, IAcmeService nwService)
{
if (fsService == null)
{
throw new ArgumentNullException("fsService");
}
if (dbService == null)
{
throw new ArgumentNullException("dbService");
}
if (nwService == null)
{
throw new ArgumentNullException("nwService");
}
this.fsService = fsService;
this.dbService = dbService;
this.nwService = nwService;
}
public IAcmeService Create(string serviceName)
{
switch case serviceName
{
case "fs":
return this.fsService;
case "db":
return this.dbService;
case "nw":
return this.nwService;
case default:
throw new ArgumentException("serviceName");
}
}
}
Вы можете сделать его более общего назначения, если вы хотите быть в состоянии Создайте произвольное количество экземпляров IacMeservice, но я оставлю это как упражнение для читателя :)
Это потребует также зарегистрировать завод с единством. В любом месте, где вам нужен Iacmeservice на основе имени, вы принимаете зависимость от IacmeserviceFactory вместо самого IacMeservice.