2016-11-07 42 views
2

我有使用DI与构造函数属性的问题。我正在根据我的IPDFBuilder构建PDFBuilderDI使用动态构造函数注入

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登记beeing完成),因为不同的控制器将对PDFBuilder类的属性使用不同的值。一个简单的解决方案就是让属性的setter公开,以便在一个操作方法中我可以设置这些值,然后调用CreatePDF()。然而这并不正确。另一种简单的解决办法是删除类的属性,只是传递的PDFBuilder作为方法属性的3个属性的CreatePDF方法是这样的:

public void CreatePDF(string templatefilename, string templatefilepath, Dictionary<string, string> dict) { 
     //Do something 
    } 

但是,现在让我们说,我PDFBuilder对子级有10种方法,这都需要这些3个属性。那么这不是正确的解决方案吗?

那么正确的解决方案是什么?我在不同的类/接口实现中多次遇到这个问题,并想在这些情况下设计一些帮助。

+1

这些参数/属性的值来自哪里?配置文件?或从用户? –

回答

4

您正在将运行时数据注入到组件的构造函数中,该构造函数为bad thing。该解决方案是将那些运行时值出构造成CreatePDF方法:

public interface IPDFBuilder 
{ 
    void CreatePDF(string templatefilepath, string templatefilename, 
     Dictionary<string, string> dict); 
} 
+0

如果这些是运行时数据,这还不是很清楚。也许这些是来自配置文件的配置数据。 –

+0

@YacoubMassad:问题陈述为“因为不同的控制器将使用不同的属性值”。这导致我得出结论,它是运行时数据。但是你是对的,它仍然可以是配置数据,这将改变答案。 – Steven

+1

对于迟到的回复,我确定运行时数据!我会将此标记为答案,因为史蒂芬给我们的链接是一个很好的指导。 –

0

你可以子类(或样机,根据您的要求)不同种类的PDFBuilders,并将其注入到根据类。

我不知道你使用的是什么DI框架,但我很确定这是一个选项,告诉框架你想在特定的类中注入什么样的依赖关系。

编辑:请记住:此解决方案不适用于运行时已知的值。

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) 
{ 
    ... 
} 

它会给你更多的flexebility在建设者的初始化,如果你deside改变他们一段时间。您也可以自由初始化此配置 - 常量,配置,数据库等。

缺点之一 - 您的配置会随着时间的推移变得非常笨拙,而且不会重构它,这对其他人来说是黑洞,所以要小心。

选择最适合您的是什么。