我有一个FTP实用程序,负责通常的FTP工作:放置文件,获取文件等。作为我们基础架构的一部分,我们要求组件从实现IConfiguration接口的组件检索其配置并将其条目记录到实现ILogger接口的组件。请注意,ftp主机是通过logicalHost名称(例如someFtpSite)描述的,该名称与配置文件中包含主机名,用户ID和密码的部分相匹配。所以我的界面和类定义是这样创建的:
public interface IFtpUtility
{
void PutFile(string sourceFileAndPath, string targetFileAndPath, string logicalHost);
}
public class FtpUtility : IFtpUtility
{
private readonly IConfiguration _configuration;
private readonly ILogger _logger;
public FtpUtility(ILogger logger, IConfiguration configuration)
{
_configuration = configuration;
_logger = logger;
}
// IFtpUtility implementation follows
}
我对此签名的意图是只在需要操作时才需要logicalHost名称(例如PutFile),因此在PutFile方法本身上提供它。
这种布局非常适合与Unity等IoC容器一起使用。我们将拥有以下代码:
UnityContainer = new UnityContainer();
UnityContainer.RegisterType<IConfiguration, ConfigurationProvider>();
UnityContainer.RegisterType<ILogger, LoggingProvider>();
UnityContainer.RegisterType<IFtpUtility, FtpUtility>();
稍后我需要使用FtpUtility时,我会依靠容器进行适当的分辨率:
IFtpUtility ftpUtility = UnityContainer.Resolve<FtpUtility>();
现在一位同事告诉我,logicalHost名称应该是构造函数的一个参数,因为没有它,没有任何函数可以执行,它或多或少与FtpUtility的特定实例相关联。我们只会在每次调用时与一个FTP服务器进行通信。所以我很高兴地将构造函数更改为包含logicalHost名称,这破坏了我的IoC容器分辨率。 请注意,虽然IConfiguration和ILogger可以与特定实现相关联,但logicalHost特定于实例,我们在创建实例之前不知道它。现在我可以争辩说这样的改变会改变我的IoC容器使用情况,因此我无法实现它等等,但是这个参数太弱了(我发现)。以下是问题:
答案 0 :(得分:1)
1,2。从抽象的角度来看,在构造函数中使用主机名是合乎逻辑的,也是理想的位置。
3,4。在我个人看来,通过统一解析主机名有点矫枉过正,但完全有可能。一个更简单的选择是实例化这是你的统一配置并从标准的app / web.config中提取主机名,类似于下面的(MVC实现);
container.RegisterType<IFtpUtility, FtpUtility>(
new InjectionConstructor(ConfigurationManager.AppSettings["Hostname"]));
这可以很好地解耦,并且仍然允许您根据需要配置该设置。
答案 1 :(得分:1)
您可以使用以下定义解析IFtpUtility
,而不是直接解析IFtpUtilityFactory
:
interface IFtpUtilityFactory
{
IFtpUtility Create(string logicalHost);
}
任何给定的FTP实用程序实现都有相应的工厂实现。它实际上是一个带有通用接口的代理构造函数,可以在解决时间之后提供所需的参数。