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

因为每种任务类型都有大量不同的关联字段,所以我认为最好用单独的类来代表每种任务类型。

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

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所需的代码。

一个基本的例子:
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.
    }
}

然后,解析器将使用与此类似的代码来创建任务集合:
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,然后返回适当的Task类的实例:
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种情况)来选择要实例化的子类。我希望可以在这里进行某种多态技巧来清理此方法。

有什么建议吗?

最佳答案

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

确保您已“使用System.Reflection”,将以下代码放入实例化方法中。

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,还可以节省动手的维护工作。

关于c# - 抽象工厂设计模式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27294/

10-12 00:23