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() 我可以使用 switch case/dictionary 和返回类型。

我如何一般地基于类型获取/创建渲染器?

我如何在这里使用工厂或抽象工厂?

或者哪种设计模式更适合这个问题?

4

2 回答 2

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);
}
于 2013-10-18T09:53:10.680 回答
1

您可以使用您的密钥为类型的工厂,本文有一些示例。

如果您负担得起使用 IoC,最好让 IoC 引擎根据字符串决定应该使用哪个具体类,您应该相应地配置您的容器。该字符串可以是类型名称。我建议使用ninject,但任何其他像windsor 这样的IoC 都可以。

下面是一个示例,说明如何使用具有通用接口的工厂来完成,因为在您的情况下,您需要传递它的构造函数。

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 更好,但这是一种有效的方法。

于 2013-10-17T15:56:56.483 回答