Fly*_*wat 21 c# design-patterns factory
我正在为我的公司开发一个内部项目,项目的一部分是能够将XML文件中的各种"任务"解析为稍后要运行的任务集合.
因为每种类型的Task都有许多不同的相关字段,所以我认为最好用一个单独的类来表示每种类型的Task.
为此,我构建了一个抽象基类:
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);
}
Run Code Online (Sandbox Code Playgroud)
每个任务都继承自此基类,并包含从传入的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.
}
}
Run Code Online (Sandbox Code Playgroud)
然后,解析器将使用与此类似的代码来创建任务集合:
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));
}
}
Run Code Online (Sandbox Code Playgroud)
所有这些都非常有效,并且允许我使用基类传递任务,同时保留为每个任务创建单独类的结构.
但是,我对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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
因为我必须解析XMLElement,所以我使用了一个巨大的(实际代码中的10-15个案例)开关来选择要实例化的子类.我希望我能在这里做一些多态的技巧来清理这个方法.
有什么建议?
Dev*_*ris 12
我用反射来做到这一点.您可以创建一个基本上扩展的工厂,而无需添加任何额外的代码.
确保你有"使用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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
另一个观察结果是,你可以将这个方法设置为静态并将其挂在Task类之外,这样你就不需要新建TaskFactory了,而且你也可以自己保存一个移动的东西来维护.
创建每个类的"Prototype"实例,并将它们放在工厂内的哈希表中,并将XML中的字符串作为键.
所以CreateTask只是通过哈希表中的get()来找到正确的Prototype对象.
然后在上面调用LoadFromXML.
你必须将类预先加载到哈希表中,
如果你想要它更自动......
您可以通过在工厂中调用静态寄存器方法来使类"自行注册".
将调用寄存器(带有构造函数)放在Task子类的静态块中.然后你需要做的就是"提及"类来运行静态块.
然后,任务子类的静态数组就足以"提及"它们.或者使用反射来提及类.