2013-08-21 25 views
15

Tôi quen với việc tạo ra các nhà máy của riêng tôi như thể hiện (điều này được đơn giản hóa để minh hoạ):Thay thế nhà máy với AutoFac

public class ElementFactory 
{ 
    public IElement Create(IHtml dom) 
    { 
     switch (dom.ElementType) 
     { 
      case "table": 
       return new TableElement(dom); 
      case "div": 
       return new DivElement(dom); 
      case "span": 
       return new SpanElement(dom); 
     } 
     return new PassthroughElement(dom); 
    } 
} 

Cuối cùng tôi nhận được xung quanh để sử dụng một container IoC (AutoFac) trong hiện tại của tôi dự án, và tôi tự hỏi là có một số cách kỳ diệu để đạt được cùng một điều thanh lịch với AutoFac?

+1

Lợi thế của việc thay thế nhà máy này bằng Autofac là gì? – Steven

+0

Xin lỗi, như tôi đã ám chỉ trong nhận xét của tôi về câu trả lời của KeithS, tôi đã hy vọng sẽ có một số voodoo AutoFac cho phép tôi tránh việc chuyển đổi. Lợi thế của việc tránh chuyển đổi là gì? I dunno ... Tôi dường như đã được truyền bá với một sự ác cảm với họ: ( –

+1

IoC không phải là cây đũa thần. Bạn có thể sử dụng tên đăng ký, và bạn có thể loại bỏ công tắc, nhưng cuối cùng sẽ luôn có một số loại Lời khuyên của tôi: sử dụng một nhà máy pháo đài của mình và đăng ký các nhà máy trong Autofac – Steven

Trả lời

23

Câu trả lời ngắn gọn: Có.

Câu trả lời dài hơn: Đầu tiên, trong trường hợp đơn giản khi một lớp Foo được đăng ký để thực hiện cho IFoo, tham số hàm xây dựng hoặc thuộc tính loại Func<IFoo> sẽ tự động được giải quyết bởi Autofac. Autofac sẽ tiêm một đại biểu về cơ bản thực hiện container.Resolve<IFoo>() khi được gọi.

Trong trường hợp phức tạp hơn như trường hợp của bạn, nơi mà sự phản xạ chính xác được trả về dựa trên các thông số đầu vào, bạn có thể thực hiện một trong hai điều. Trước tiên, bạn có thể đăng ký một phương pháp nhà máy như giá trị trả về của nó để cung cấp một giải pháp tham số:

builder.Register<IElement>((c, p) => { 
    var dom= p.Named<IHtml>("dom"); 
    switch (dom.ElementType) 
    { 
     case "table": 
      return new TableElement(dom); 
     case "div": 
      return new DivElement(dom); 
     case "span": 
      return new SpanElement(dom); 
    } 
    return new PassthroughElement(dom); 
    }); 

//usage 
container.Resolve<IElement>(new NamedParameter("dom", domInstance)) 

Đây không phải là loại an toàn (domInstance sẽ không được biên dịch kiểm tra để đảm bảo nó là một IHtml), cũng không phải rất dọn dẹp. Thay vào đó, một giải pháp khác là để thực sự đăng ký phương pháp nhà máy như một Func:

builder.Register<Func<IHtml, IElement>>(dom => 
{ 
    switch (dom.ElementType) 
    { 
     case "table": 
      return new TableElement(dom); 
     case "div": 
      return new DivElement(dom); 
     case "span": 
      return new SpanElement(dom); 
    } 
    return new PassthroughElement(dom); 
}); 


public class NeedsAnElementFactory //also registered in AutoFac 
{ 
    protected Func<IHtml,IElement> CreateElement {get; private set;} 

    //AutoFac will constructor-inject the Func you registered 
    //whenever this class is resolved. 
    public NeedsAnElementFactory(Func<IHtml,IElement> elementFactory) 
    { 
     CreateElement = elementFactory; 
    } 

    public void MethodUsingElementFactory() 
    { 
     IHtml domInstance = GetTheDOM(); 

     var element = CreateElement(domInstance); 

     //the next line won't compile; 
     //the factory method is strongly typed to IHtml 
     var element2 = CreateElement("foo"); 
    } 
} 

Nếu bạn muốn giữ các mã trong ElementFactory thay vì đặt nó trong module Autofac, bạn có thể làm cho phương thức tĩnh và đăng ký đó (điều này đặc biệt hữu ích trong trường hợp của bạn vì phương pháp nhà máy của bạn được tạo ra không đáng kể):

public class ElementFactory 
{ 
    public static IElement Create(IHtml dom) 
    { 
     switch (dom.ElementType) 
     { 
      case "table": 
       return new TableElement(dom); 
      case "div": 
       return new DivElement(dom); 
      case "span": 
       return new SpanElement(dom); 
     } 
     return new PassthroughElement(dom); 
    } 
} 

... 

builder.Register<Func<IHtml, IElement>>(ElementFactory.Create); 
+1

Cảm ơn, đó là thực sự hữu ích Tôi hy vọng AutoFac sẽ giúp tôi tránh được tuyên bố chuyển đổi xấu xí, nhưng có nó, nhìn chằm chằm vào tôi, thực tế chế nhạo tôi, trong cả ba khối mã của bạn :) –

+2

Cũng có thể sử dụng "đăng ký khóa", chỉ định từng tên loại phần tử làm khóa cho phương thức phân giải cho loại đối tượng tương ứng. Biến chứng trong tình huống này là không phải tất cả các kiểu trả về có thể được liên kết với một khóa (bạn có một trường hợp mặc định), và cha mẹ IHtml của tên phần tử là cần thiết vì các lý do khác. Vì vậy, nó có vẻ dễ dàng nhất chỉ để lấy mã làm việc của bạn và thiết lập nó để AutoFac có thể sử dụng nó. – KeithS

+2

Việc đăng ký không biên dịch: 'builder.Register > (ElementFactory.Create);' Tôi mong đợi nó trông giống như thế này: 'builder.Register > ((context, parameters) => (html => ElementFactory.Create (html))); ' –

Các vấn đề liên quan