我正在开发将HTML文档转换为Word文档的库。这是通过遍历HTML文档并逐一处理HTML元素来完成的。有一系列的类来处理每个HTML标签。
public abstract class DocxElement
{
public void Process();
}
public class DocxTable : DocxElement
{
public override void Process(){}
}
public class DocxDiv : DocxElement
{
public override void Process(){}
}
以上类负责处理其html对应项。因此,每当我扩展该库以支持其他html标记时,我都会从DocxElement创建一个子类。当HTML解析器遇到HTML标记时,它使用工厂类来生成对应的DocxElement类。
public class ElementFactory
{
public DocxElement Resolve(string htmlTag)
{
switch(htmlTag)
{
case "table":
return new DocxTable();
case "div":
return new DocxDiv();
}
}
}
现在,我认为它违反了开放封闭原则。我宁愿不仅仅因为设计模式需要反射而使用反射。因此,我创建了一个单例字典来注册元素类。
Dictionary<string, Func<DocxElement>> doc;
doc.Add("table",()=>{ new DocxTable();});
最终,我能够消除switch语句。创建新的子类时,仍然需要向字典中添加元素。
有没有更好的方法可以做到这一点?请指教。
最佳答案
我会说您的Dictionary
方法很好。任何其他尝试使该类通用的东西都将丢失静态编译时间检查。如果准备牺牲编译时间检查,则可以使用反射使此代码通用。
public class ElementFactory
{
public DocxElement Resolve(string htmlTag)
{
var type = Type.GetType(string.Format("{0}.Docx{1}",
typeof(ElementFactory).Namespace,
CultureInfo.CurrentCulture.TextInfo.ToTitleCase(htmlTag)));
return (DocxElement)Activator.CreateInstance(type);
}
}
如何使用:
ElementFactory factory = new ElementFactory();
var table = factory.Resolve("table");//Works
var div = factory.Resolve("div");//Works
var span = factory.Resolve("span");//Explodes!!
如您所见,由于多种原因,这可能会使运行时失败。找不到类型,找到了类型,但是没有公共的无参数构造函数,找到了类型,但是它不是从
DocxElement
派生的,等等。因此,最好使用
Dictionary
选项IMO。