根据参数使用不同依赖关系时的依赖关系策略
本文关键字:关系 依赖 策略 参数 | 更新日期: 2023-09-27 18:24:27
具有此接口:
public interface FileManager {
string UploadFile(HttpPostedFileBase file);
string UploadFile(Uri uri);
}
我的实现看起来像:
public class FileManagerAzure : FileManager {
private FileParser parser;
FileManagerAzure(FileParser parser){
this.parser = parser; // Can this be a constructor injection??
}
public string UploadFile(HttpPostedFileBase file) {
return parser.Parse(file); // Should I Inject the parser here depending on type ??
}
public string UploadFile(Uri uri) {
return parser.Parse(uri);
}
}
这依赖于FileParser,它看起来如下:
public interface FileParser {
string Parse(object source)
}
理想情况下,我希望有一些解析器实现(当然这不起作用):
public class FileParserHttpPostedFileBase : FileParser {
string Parse(HttpPostedFileBase source) {
return file.FileName;
}
}
public class FileParserUri : FileParser {
string Parse(Uri source) {
return Uri.ToString();
}
}
有没有根据传递给
UploadFile()
的参数创建具体的解析器依赖项?这一定是setter注入?这好吗?或者我可以采取其他策略吗?我必须使我的
FileParser
接口接收一个对象作为源。这听起来不应该,因为我有一个有限的允许输入类型集,当然不是object
。在这种情况下为CCD_ 4和CCD_。我如何限制这个范围?
您可以通过构造函数注入依赖项。只要有可能,我都会选择这种方式。这意味着您不能使用IoC容器进行实例化。您可以使用抽象工厂模式来封装要注入什么具体解析器的决策,并让IoC容器将具体工厂注入调用类。
不过,这似乎有些过头了。既然FileManager
接口公开了两种参数类型的方法,为什么不同时注入两种解析器类型呢?为此,我会使FileParser
类型通用,这样您就不需要为每个新的解析器都有一个新的接口。
public interface FileParser<T>
{
string Parse(T value);
}
public class UriParser : FileParser<Uri>
{
string Parse(Uri value)
{
// implementation
}
}
你可以这样实现FileManagerAzure
:
public class FileManagerAzure : FileManager {
private FileParser<Uri> uriParser;
private FileParser<HttpPostedFileBase> postedFileParser;
FileManagerAzure(FileParser<Uri> uriParser, FileParser<HttpPostedFileBase> postedFileParser){
this.uriParser = uriParser;
this.postedFileParser = postedFileParser;
}
public string UploadFile(HttpPostedFileBase file) {
return this.postedFileParser.Parse(file);
}
public string UploadFile(Uri uri) {
return this.uriParser.Parse(uri);
}
}
这个实现可以通过IoC容器实例化,也没有问题。
我认为您应该使用泛型类型:
public interface FileParser<T> {
string Parse(T source)
}
通过这种方式,您可以轻松地实现以下多个实现:
public class FileParserHttpPostedFileBase : FileParser<HttpPostedFileBase> {
public string Parse(HttpPostedFileBase source) {
return file.FileName;
}
}
public class FileParserUri : FileParser<Uri> {
public string Parse(Uri source) {
return Uri.ToString();
}
}
通过这种方式,您可以消除设计中的歧义,因为现在可以清楚地向构造函数中注入什么:
public class FileManagerAzure : FileManager {
private FileParser<HttpPostedFileBase> httpParser;
private FileParser<Uri> uriParser;
FileManagerAzure(FileParser<HttpPostedFileBase> httpParser,
FileParser<Uri> uriParser){
this.httpParser = httpParser;
this.uriParser = uriParser;
}
public string UploadFile(HttpPostedFileBase file) {
return httpParser.Parse(file);
}
public string UploadFile(Uri uri) {
return uriParser.Parse(uri);
}
}
但是,如果FileManagerAzure
像这样只委托它的依赖项,那么您应该质疑FileManager
抽象是否有任何用处。FileManager
的使用者可以直接依赖于FileParser<T>
抽象中的一个。如果FileParser<T>
只有那一行代码,我们甚至可以争辩说,您甚至可能希望不使用这种抽象(然而,一如既往:您的里程可能会有所不同)。