2013-07-19 37 views
0

我有一个业务层,其中只有一个类应该是外部世界可见的。所以,我已经把所有的班级都标记为内部,除了那个班级。由于该类需要一些内部类来实例化,因此我需要将其他类标记为public,其他类依赖于其他类等。所以最终几乎所有我的内部课程都公开了。确实依赖注入促进门面?

你如何处理这种情况?

此外,今天只有一类暴露于外部世界,但未来可能会有两个或三个,所以这意味着我需要三个外立面?

感谢

+0

这种依赖注入是如何进行的?事实上,你的设计促进了外墙。这是外部代码访问故意隐藏类的唯一方式(除了InternalsVisibleTo)。 –

+0

你的意思是你的一个公共类取决于内部类(通过构造函数/属性注入)? – Matthew

+0

@Matthew是的,这正是我想通过构造器注入(最好) – shankbond

回答

1

做了很多的研究,我写我的研究结果,因此,它可能是一些帮助,以新人的依赖注入


误区关于我目前的设计和依赖注入后:

初始方法以及与之相关的问题:

我的业务层有一个组合根,其中 它应该在业务层之外并且靠近应用程序 入口点。在组成方面,我基本上有一个大工厂,称为Poor Man's DI by Mark Seemann。在我的应用程序起点上,我创建了这个工厂类的一个实例,然后创建了我的唯一(打算是)可见类到外部世界。这个决定显然违反Liskov's Principle这说明每个依赖应该是可替换的。我有一个模块化设计,但我以前的方法是紧密结合的,尽管只有一些代码清洁和代码可维护性,但我无法从中获得更多的好处。

更好的方法是:

A very helplful link given by Facio Ratio

的构成根应该是应用程序的根附近的所有依赖类应该公之于众我提到最初是一个问题;使他们公开我引入低耦合和跟随Liskov的替代是好的。

1

可以在公共类更改为界面和程序的其他部分将只知道大概的接口。这里有一些示例代码来说明这一点:

public interface IFacade 
{ 
    void DoSomething(); 
} 

internal class FacadeImpl : IFacade 
{ 
    public FacadeImpl(Alfa alfa, Bravo bravo) 
    { 
    } 

    public void DoSomething() 
    { 
    } 
} 

internal class Alfa 
{ 

} 

internal class Bravo 
{ 

} 
+0

阿尔法,布拉沃很有趣:) – shankbond

+0

SO你说我确实需要一个门面? – shankbond

+1

我想说的是公开接口而不是类是好的做法,它可以让你轻松地改变它的内部逻辑并隐藏来自外部世界的实现细节。 –

1

正确,您的组合根目录中的所有注入依赖项必须可见。这听起来像你问这个问题:Ioc/DI - Why do I have to reference all layers/assemblies in entry application?

引述马克·西曼说一部分答案:

你不必硬引用添加到所有需要的库。相反,您可以使用基于约定的程序集扫描(首选)或XML配置的形式使用后期绑定。

而且这一点,从史蒂芬:

如果你是非常严格的使用组件保护您的建筑界,你可以简单的构图根移动到一个单独的程序。

但是,你应该问自己为什么这样做值得付出。如果仅仅是为了强化建筑界限,那么就没有纪律的替代品。我的经验是,遵循SOLID原则时,该规则也更易于维护,因为依赖注入是“粘合剂”。

0

我可以看到三个解决方案,没有真正的好处。您可能想要将它们合并在一起。但是...

首先,在构造函数中放入一些简单的参数(数字,或许),让调用者说出他想做什么,并且新的公共类实例可以用来获取内部类对象-注入)。 (您可以使用特殊的公共类/接口,这些接口仅用于在此传递信息。)这会造成一个尴尬和有限的接口,但对于封装非常有用。如果调用者更喜欢添加一些快速参数来构建复杂的可注入对象,那么这可能会奏效。 (当一个方法需要五个你从未听说过的类的对象时,当你需要或者甚至想要的唯一选项是“只读”和“可编辑”时,这总是一种拖拽。)

其次,你可以制作你的内部类是公开的。现在来电者拥有巨大的权力,可以做任何事情。如果调用代码真的是系统的核心,那么这很好,但如果你不太相信代码或者调用者真的不想被所有挑剔的细节困扰,那就很糟糕。

第三,你可能会发现你可以从调用代码中拉出一些类到你的程序集中。如果你真的很幸运,那么打电话的班级可能会在内部工作得更好(希望不会把这个问题重新引入一级)。

回应评论:

据我了解,你有一个服务调用一个公共类的方法在业务层。要进行调用,它需要业务层中其他类的对象。这些其他类是并且应该是内部的。例如,您想调用一个名为GetAverage的方法,并将其传递给(内部)类RoundingPolicy的一个实例,以便知道如何进行四舍五入。我的第一个回答是,你应该采用一个整数值而不是一个类:一个常量值,例如ROUND_UP,ROUND_DOWN,NEAREST_INTEGER等。然后,GetAverage将使用此数字在业务层内生成适当的RoundingPolicy实例,从而使RoundingPolicy保持内部。

我的第一个答案是我建议的。然而,它给服务提供了一个相当原始的界面,所以我的第二个答案提出了替代方案。

第二个答案实际上是你试图避免的。我的想法是,如果服务所需的所有内部类都是,可能没有办法解决问题。在我上面的示例中,如果服务在传递它之前使用30行代码构建正确的RoundingPolicy实例,那么您将不会使用几个整数参数来解决问题。你需要给整体设计很多想法。

第三个答案是一个孤独的希望,但您可能会发现调用代码正在做的工作,可以很容易地在业务层内完成。这实际上类似于我的第一个答案。然而,在这里,界面可能更优雅。我的第一个答案限制了服务的功能。这个答案表明该服务不想做太多事情;它总是使用一个相同的RoundingPolicy实例,因此您甚至不需要传递参数。

我可能没有完全理解你的问题,但我希望在这里有一个想法,你可以使用。

还有更多:第四答:

我认为这是一个有点我的第一个答案的一部分,但我已经想通了,认为我应该明确说明它。

我不认为你要调用的类需要一个接口,但是你可以为所有你不想公开的接口提供接口。例如IRoundingPolicy。您将需要一些方法来获得这些接口的实际实例,因为new IRoundingPolicy()不起作用。现在该服务暴露于您试图隐藏的所有类的复杂性(向下),但他们无法在类内看到(正面)。您可以精确地控制服务的功能 - 原始类仍然是封装的。这也许使我的第二个答案成为可行的版本。这可能是有用的一个或两个地方的服务需要更多精心选择比我的第一个答案允许。

+0

对于第二种方法,我认为只公开与外界相关的类是一个好主意。但是在你的方法中,我需要将所有的依赖关系及其依赖关系暴露给外部世界,这些都是无关紧要的。 – shankbond

+0

对于第三种方法,调用类不过是一种服务,正在做实际工作的主要类都封装在业务层组件中。在该服务的启动方法上,我只创建该公共类的一个实例,并在独立线程上调用其唯一的公开类方法。 – shankbond

+0

@RalphChaping对于你的第一种方法,我不明白你在说什么? – shankbond