2013-10-17 86 views
0

我使用MigraDoc創建PDF文檔。如何將其轉換爲工廠/抽象工廠?

我有類似於MigraDoc中使用的商業實體。

public class Page{ 
     public List<PageContent> Content { get; set; } 
    } 


    public abstract class PageContent { 

     public int Width { get; set; }  
     public int Height { get; set; } 
     public Margin Margin { get; set; } 
    } 

    public class Paragraph : PageContent{ 
     public string Text { get; set; }  
    } 

    public class Table : PageContent{ 
     public int Rows { get; set; }  
     public int Columns { get; set; } 
     //.... more 
    } 

在我的業務邏輯,有渲染類爲每種類型的

public interface IPdfRenderer<T> 
{ 
    T Render(MigraDoc.DocumentObjectModel.Section s); 
} 

class ParagraphRenderer 
    : IPdfRenderer<MigraDoc.DocumentObjectModel.Paragraph> 
{ 
    BusinessEntities.PDF.Paragraph paragraph; 

    public ParagraphRenderer(BusinessEntities.PDF.Paragraph p) 
    { 
    paragraph = p; 
    } 

    public MigraDoc.DocumentObjectModel.Paragraph Render(MigraDoc.DocumentObjectModel.Section s) 
    { 
     var paragraph = s.AddParagraph(); // add text from paragraph etc 
     return paragraph; 
    } 
} 


public class TableRenderer : IPdfRenderer<MigraDoc.DocumentObjectModel.Tables.Table> 
{ 
    BusinessEntities.PDF.Table table; 
    public TableRenderer(BusinessEntities.PDF.Table t) 
    { 
     table =t; 
    } 
    public MigraDoc.DocumentObjectModel.Tables.Table Render(Section obj) 
    { 
     var table = obj.AddTable(); 
     //fill table based on table 
    } 
} 

我想創建一個PDF頁面:

  var document = new Document(); 
      var section = document.AddSection();// section is a page in pdf 
      var page = GetPage(1); // get a page from business classes 
      foreach (var content in page.Content) 
      { 
         //var renderer = createRenderer(content); // 
        // get Renderer based on Business type ?? 
        // renderer.Render(section) 
      } 

對於createRenderer()我可以用開關大小寫/字典和返回類型。

我該如何獲得/創建一般基於類型的渲染器?

如何在這裏使用工廠或抽象工廠?

或者哪種設計模式更適合這個問題?

回答

1

你可以使用一個工廠,你的鑰匙將是類型,this文章有一些例子。

如果您可以負擔得起使用IoC,那麼如果您讓IoC引擎根據字符串決定應使用哪個具體類,則應該更好地配置您的容器。該字符串可以是類型名稱。 我建議ninject,但任何其他IoC像windsor可以工作。

下面是如何使用具有通用接口的工廠完成的示例,因爲在您的情況下,您需要傳遞的是構造函數。

public class Factory<T> 
{ 
    public Factory() 
    { 
     _Mappings = new Dictionary<string,Func<IInterface<T>>>(2); 

     _Mappings.Add("MyClass1",() => new MyClass1() as IInterface<T>); 
     _Mappings.Add("MyClass2",() => new MyClass2() as IInterface<T>); 
    } 
    public IInterface<T> Get(string typeName) 
    { 
     Func<IInterface<T>> func; 
     if (_Mappings.TryGetValue(typeName, out func)) 
     { 
      return func(); 
     } 
     else 
      throw new NotImplementedException(); 
    } 

    readonly Dictionary<string, Func<IInterface<T>>> _Mappings; 
} 

public class MyClass1 : IInterface<int> 
{ 
    public int Method() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class MyClass2 : IInterface<string> 
{ 
    public string Method() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public interface IInterface<T> 
{ 
    T Method(); 
} 

我仍然認爲IoC更好,但這是一種有效的方法。

+0

請你能解釋一下嗎?我無法將文章映射到我的情況。 – Amitd

+0

下面是一個使用相同概念但使用類型名稱作爲關鍵字的工廠示例。您應該將您的通用接口替換爲您的通用接口。你需要在工廠傳遞一個額外的參數來填充你的構造函數。 – arturomonriv

+0

公共類廠 { 公共工廠() { _Mappings =新詞典<字符串,函數功能 >>(2); _Mappings.Add(「MyClass1」,()=> new MyClass1()as IInterface ); _Mappings。添加(「MyClass2」,()=> new MyClass2()as IInterface ); } – arturomonriv

1

您的接口定義可以增強。相反,只要將泛型和接受輸入作爲構造函數返回,您既可以接受通用輸入,也可以返回它。

public interface IPdfRenderer<T> 
{ 
    T Render(MigraDoc.DocumentObjectModel.Section s, T baseContent); 
} 

然後擴大arutromonriv的回答,

public class DynamicRenderer : IPdfRenderer<PageContent> 
{ 
    public DynamicRenderer(IPdfRenderer<Paragraph> paragraph 
     , IPdfRenderer<Table> table){ 
     //variable assignment 
    } 
    public PageContent Render(MigraDoc.DocumentObjectModel.Section s, PageContent baseContent){ 
     if(baseContent is Paragraph){ return paragraph.Render(s, baseContent as Paragraph); } 
     else{ return table.Render(s, baseContent as Table); } 
    } 
} 

有了這個,你可以這樣做:

var renderer = createRenderer(); // 
foreach (PageContent content in page.Content) 
{ 
    // get Renderer based on Business type ?? 
    renderer.Render(section, content); 
}