使用DI和构造函数属性时遇到问题。我正根据PDFBuilder
建立IPDFBuilder
。
public interface IPDFBuilder
{
string templatefilepath { get; }
string templatefilename { get; }
Dictionary<string, string> dict { get; }
void CreatePDF();
}
public class PDFBuilder : IPDFBuilder
{
public string templatefilename { get; private set; }
public string templatefilepath { get; private set; }
public Dictionary<string, string> dict { get; private set; }
public PDFBuilder(string templatefilename, string templatefilepath, Dictionary<string, string> dict)
{
this.templatefilename = templatefilename;
this.templatefilepath = templatefilepath;
this.dict = dict;
}
public void CreatePDF() {
//Do something
}
}
此PDFBuilder
可以并将在多个控制器中使用,例如:
public class KeuringController : Controller
{
private IPDFBuilder _PDFBuilder;
public KeuringController(IPDFBuilder pdfBuilder)
{
_PDFBuilder = pdfBuilder;
}
//Action methods that use `PDFBuilder` below...
}
但是,我无法在启动类中设置PDFBuilder
的属性(DI注册已完成),因为不同的控制器将对PDFBuilder
类的属性使用不同的值。一个简单的解决方案就是将属性的setter设置为public,这样在一个action方法中我可以设置值,然后调用CreatePDF()
。然而,这感觉不对。另一个简单的解决方案是删除类属性,并将PDFBuilder
的3个属性作为方法属性传递给CreatePDF
方法,如下所示:
public void CreatePDF(string templatefilename, string templatefilepath, Dictionary<string, string> dict) {
//Do something
}
但现在让我们说PDFBuilder
有10种方法都需要这3种属性。那么这不是正确的解决方案吗?
那么正确的解决方案是什么?我使用不同的类/接口实现多次遇到这个问题,并希望在这些情况下有一些设计帮助。
答案 0 :(得分:4)
您正在将运行时数据注入组件的构造函数,即bad thing。解决方案是将那些运行时值从构造函数中移出到CreatePDF
方法:
public interface IPDFBuilder
{
void CreatePDF(string templatefilepath, string templatefilename,
Dictionary<string, string> dict);
}
答案 1 :(得分:0)
您可以将不同类型的PDFBuilders子类化(或原型,取决于您的要求)并将它们注入到相应的类中。
我不知道您正在使用什么DI框架,但我非常确定可以告诉框架您希望在特定类中注入哪种依赖项。
编辑:请记住:此解决方案不适用于运行时已知的值。
答案 2 :(得分:0)
有两种方法可以做你想做的事:
1) Create factory for builder.
2) Create configurator for builder.
创建工厂时,您基本上指定了对象的创建方式,因此可以自由地将所需的一切设置为不同构建器的不同实现:
public inteface IPDFBuilderFactory
{
IPDFBuilder Create();
}
您需要传递所有依赖项 - 这是一个缺点。我个人不喜欢这种方法。
另一种方法是创建如下配置:
public interface IPDFConfiguration
{
string templatefilename {get;}
string templatefilepath {get;}
Dictionary<string, string> dict {get;}
}
并将其作为参数传递给构造函数:
public PDFBuilder(IPDFConfiguration configuration)
{
...
}
如果您希望在一段时间内更改它们,它将为您的构建器初始化提供更多灵活性。您也可以自由初始化此配置 - 常量,配置,数据库等。
缺点之一 - 随着时间的推移,你的配置会变得非常笨拙,如果没有重构,它将成为其他人的黑洞,所以要小心。
选择最适合您的方式。