我有一个有多个实现的接口(称之为IAcmeService)。
FileSystemAcmeService
DatabaseAcmeService
NetworkAcmeService
最终用户需要能够选择将使用哪种实现,并保存该选择。
目前我正在配置我的IOC容器(Unity)以注册所有已知的名称实现。
container.RegisterType(of IAcmeService, FileSystemAcmeService)("FileSystemAcmeService")
container.RegisterType(of IAcmeService, DatabaseAcmeService)("DatabaseAcmeService")
container.RegisterType(of IAcmeService, NetworkAcmeService)("NetworkAcmeService")
为了让用户保存他们的选择,我有app.config配置部分文件,用于存储要使用的所选服务名称。
要解决所选的实现,我正在使用该服务的类的Initialize方法中进行手动解析。
Private _service as IAcmeService
Public Sub Initialize()
_service = container.Resolve(of IAcmeService)(_config.AcmeServiceName)
End Sub
这似乎不对,因为我的班级必须知道容器。但我无法想出另一种方式。
在没有课程了解容器的情况下,是否还有其他方法可以允许最终用户选择?
答案 0 :(得分:9)
定义和实施Abstract Factory是此类问题的标准解决方案。如果你原谅我使用C#,你可以像这样定义一个IAcmeServiceFactory接口:
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实例,则可以使其更具通用性,但我会将其作为练习留给读者:)
这也要求您在Unity中注册Factory。在任何需要基于名称的IAcmeService的地方,您需要依赖IAcmeServiceFactory而不是IAcmeService本身。