我正在使用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和return type。
如何根据类型一般获取/创建渲染器?
我如何在这里使用工厂或抽象工厂?
或者哪种设计模式更适合这个问题?
答案 0 :(得分:1)
您可以使用您的密钥类型的工厂,this文章有一些示例。
如果您能够负担得起使用IoC,如果您让IoC引擎根据字符串决定应该使用哪个具体类,那么您应该相应地配置容器。该字符串可以是Type name。 我建议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更好,但这是一种有效的方法。
答案 1 :(得分: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);
}