autofac/c#:特定基类的通用工厂?

Nic*_*eld 3 c# factory dependency-injection autofac

autofac是否可以创建只能解析特定基类类型的通用工厂?

我现在看到改造一个'brownfield'c#项目使用autofac是多么可行.该项目需要创建一个不同类型但具有相同基类的组件树.这些组件需要身份验证和数据库服务(以及其他内容),因此很难只拥有空构造函数.

因此,工厂可以创建导出基类的对象,使用autofac扫描这些类,并为它们提供工厂.我认为如果你不必为每个类提供工厂,它可能会更容易构建组件对象树.

除此之外,还是这是一个糟糕设计的标志?组件和树应该尽可能少地执行,我们将此树传递给其他服务以提供处理和呈现吗?

像(哪里?是神秘工厂)的东西

public MyBase { 
    public Add(MyBase x) {..}
}

public DerivedA: MyBase {}

public DerivedB : MyBase {}

public DerivedC : DerivedA {}

public SomethingElse
{
     private ? _myBaseFact;

     public SomethingElse(? myBaseFact) { 
            _myBaseFact = myBaseFact;
     }

     public BuildComponentTree() {
        DerivedA a = _myBaseFact<DerivedA>();
        DerivedB b = _myBaseFact<DerivedB>();
        DerivedC c = _myBaseFact<DerivedC>();
        a.Add(b);
        b.Add(c);
     }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我被要求一个更具体的例子,这是公平的:)有框架组件,我想允许开发人员创建自己的组件,而无需注册autofac.拥有工厂类意味着开发人员必须将自定义组件添加到此工厂吗?请原谅这个例子,这与我遇到它时框架的工作原理类似.

FwComponent {
    public FwComponent (DataProvider, AuthManager, OtherModule)
    public Add(FwComponent x);
    public Setup();
    public Process();
    public Render();
}

Page : FwComponent {
    public Page(DataProvider, AuthManager, OtherModule): base(..)
    public string Title;
    ...
}

Input: FwComponent {
    public Input(DataProvider, AuthManager, OtherModule): base(..)
    public string Name;
    public int length;
    ...
}

Button: FwComponent {
    public Button(DataProvider, AuthManager, OtherModule): base(..)
    public string Name;
    ...
}

----

MyCustomButton : Button {
     public MyCustomButton(DataProvider, AuthManager, OtherModule): base(..)
}

MyPersonalPage : FwComponent {

    IContext _container;

    public MyPersonalPage(DataProvider, AuthManager, OtherModule, IContext container): base(..)

    public Setup() {
         var input = _container.Resolve<Input>();
         input.Name = 'xxx';
         input.length = 10;
         Add(input);

         var butt = _container.Resolve<MyCustomButton>();
         butt.name = "xxx";
         Add(butt);    
    }

    public Process() {
        DataProvider.DoStuff();
    }
}
Run Code Online (Sandbox Code Playgroud)

Dom*_*nic 5

正如我在对史蒂文的答案的评论中提到的,你的问题似乎是基于对工厂模式和多态性的目的的误解.我会留下他的答案,但让我们对你依赖注入的误解...

1)依赖注入是指服务,而不是实体

目前尚不清楚你的组件和树是什么,但我猜它们是你域中的实体,而不是对它们进行处理的服务.依赖注入用于将服务(在最一般意义上)注入到其他服务或粘合层中.示例包括将存储库注入MVC​​控制器,或将Twitter发布Web服务注入视图模型,或将产品工厂注入产品操作服务.

2)依赖注入及其框架与工厂模式无关

虽然它被命名为AutoFac,它不是某种自动马蒂奇FAC保守党发生器,任何比团结更是所有的类统一成一个方式或者温莎城堡是一个......呃......我不知道.这两个概念可能具有的唯一联系是工厂是您注入的上述服务之一.

3)依赖注入取决于良好的设计

也就是说,您必须使用适当的面向对象的注意事项,比如使用构造函数来构造类.虽然我怀疑树中的组件是实体(如上所述),但如果它们是服务,那么Add方法将违背这些设计原则:如果一个类需要一个实例MyBase,它应该将其作为构造函数参数,适当的保护条款,如果不满足此不变量则抛出异常.类似地,SomethingElse显然需要一个组件树,它可以由根节点指定:那么它应该将该根节点作为构造函数参数.


换句话说,树状情况的依赖注入友好版本最终会看起来像

interface INotificationService { }
class TwitterNotificationService : INotificationService { }
class FacebookNotificationService : INotificationService { }
class CompositeNotificationService : INotificationService
{
    public CompositeNotificationService(IEnumerable<NotificationService> services) { }
    // implement composite pattern
}

class NotificationController : Controller
{
    public NotificationController(INotificationService service)
    {
        if (service === null)
        {
            throw new ArgumentNullException("service");
        }

        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

后来,如果你使用穷人的DI,你会做类似的事情

var controller = new NotificationController(
        new CompositeNotificationService(new []
        {
            new TwitterNotificationService(),
            new FacebookNotificationService()
        }));
Run Code Online (Sandbox Code Playgroud)

DI框架的目的只是将诸如此类的样板构造代码移动到应用程序中的一个中心位置(组合根),从应用程序中有效地删除服务构造并将其转换为配置细节.但是你的应用程序需要对DI友好,这实际上只是意味着符合基本的OO原则,比如使用构造函数,以便DI工作.