首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >抽象工厂设计模式

抽象工厂设计模式
EN

Stack Overflow用户
提问于 2008-08-26 02:35:31
回答 10查看 4.9K关注 0票数 21

我正在为我的公司做一个内部项目,该项目的一部分是能够将XML文件中的各种“任务”解析为稍后要运行的任务集合。

因为每种类型的Task都有许多不同的相关字段,所以我决定最好用一个单独的类来表示每种类型的Task。

为此,我构造了一个抽象基类:

代码语言:javascript
复制
public abstract class Task
{
    public enum TaskType
    {
        // Types of Tasks
    }   

    public abstract TaskType Type
    {
        get;
    }   

    public abstract LoadFromXml(XmlElement task);
    public abstract XmlElement CreateXml(XmlDocument currentDoc);
}

每个任务都继承自这个基类,并包含从传入的XmlElement创建自身以及将自身序列化为XmlElement所需的代码。

一个基本的例子:

代码语言:javascript
复制
public class MergeTask : Task
{

    public override TaskType Type
    {
        get { return TaskType.Merge; }
    }   

    // Lots of Properties / Methods for this Task

    public MergeTask (XmlElement elem)
    {
        this.LoadFromXml(elem);
    }

    public override LoadFromXml(XmlElement task)
    {
        // Populates this Task from the Xml.
    }

    public override XmlElement CreateXml(XmlDocument currentDoc)
    {
        // Serializes this class back to xml.
    }
}

然后,解析器将使用类似下面的代码来创建任务集合:

代码语言:javascript
复制
XmlNode taskNode = parent.SelectNode("tasks");

TaskFactory tf = new TaskFactory();

foreach (XmlNode task in taskNode.ChildNodes)
{
    // Since XmlComments etc will show up
    if (task is XmlElement)
    {
        tasks.Add(tf.CreateTask(task as XmlElement));
    }
}

所有这些都工作得很好,并且允许我使用基类传递任务,同时保留每个任务都有单独类的结构。

然而,我对我的TaskFactory.CreateTask代码并不满意。此方法接受XmlElement,然后返回相应任务类的实例:

代码语言:javascript
复制
public Task CreateTask(XmlElement elem)
{
    if (elem != null)
    {
        switch(elem.Name)
        {
            case "merge":
                return new MergeTask(elem);
            default:
                throw new ArgumentException("Invalid Task");
        }
    }
}

因为我必须解析XMLElement,所以我使用了一个巨大的(在真实代码中为10-15个案例)开关来挑选要实例化的子类。我希望我能在这里做一些多态的技巧来清理这个方法。

有什么建议吗?

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2008-08-26 02:45:01

我使用反射来做这件事。您可以创建一个基本上可以扩展的工厂,而不必添加任何额外的代码。

确保你有“使用System.Reflection",把下面的代码放在你的实例化方法中。

代码语言:javascript
复制
public Task CreateTask(XmlElement elem)
{
    if (elem != null)
    { 
        try
        {
          Assembly a = typeof(Task).Assembly
          string type = string.Format("{0}.{1}Task",typeof(Task).Namespace,elem.Name);

          //this is only here, so that if that type doesn't exist, this method
          //throws an exception
          Type t = a.GetType(type, true, true);

          return a.CreateInstance(type, true) as Task;
        }
        catch(System.Exception)
        {
          throw new ArgumentException("Invalid Task");
        }
    }
}

另一个观察结果是,您可以将此方法设为静态方法,并将其从Task类挂起,这样您就不必重新创建TaskFactory,而且还可以为自己节省一个需要维护的活动部分。

票数 12
EN

Stack Overflow用户

发布于 2008-08-26 05:00:22

创建每个类的“原型”实例,并将它们放在工厂内的哈希表中,使用XML中预期的字符串作为键。

因此,CreateTask只是通过从哈希表中使用get()来找到正确的原型对象。

然后在上面调用LoadFromXML。

您必须将类预先加载到哈希表中,

如果你想让它更自动..。

您可以通过在工厂中调用静态注册方法来使类“自注册”。

将对register的调用(使用构造函数)放在Task子类的静态块中。然后,您所需要做的就是“提及”类来运行静态块。

然后,一个静态的Task子类数组就足以“提及”它们。或者使用反射来提到这些类。

票数 6
EN

Stack Overflow用户

发布于 2008-08-26 03:19:16

你对依赖注入有什么看法?我使用的是Ninject,它的上下文绑定支持非常适合这种情况。查看此blog post,了解如何使用上下文绑定在请求控制器时使用IControllerFactory创建控制器。这应该是一个很好的资源,告诉你如何根据你的情况使用它。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27294

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档