我有一个可换肤的控件库,它从外部xml文件加载控件设置/属性。
Xml
类在一个单独的项目中,因为它们将在皮肤编辑器应用程序中使用,现在问题是,控件接受构造函数中的xml对象来构建Control
,但我需要找到一个创建每个控件的好方法。
Xml类示例:
[Serializable]
[XmlInclude(typeof(XmlButton))]
[XmlInclude(typeof(XmlGroup))]
[XmlType(TypeName="Control")]
public class XmlControl
{
[DefaultValue(0)]
public int Width { get; set; }
[DefaultValue(0)]
public int Height { get; set; }
...
和每个控件类型的派生类型
[Serializable]
[XmlType(TypeName = "Button")]
public class XmlButton : XmlControl
{
public string Label { get; set; }
}
控制类
public class GUIControl : GUI3DBase
{
public GUIControl(XmlControl skinXml)
{
SkinXml = skinXml;
...
public class GUIButton : GUIControl, IActionControl
{
public GUIButton(XmlControl skinXml) : base(skinXml)
{
}
...
现在这是我需要帮助的地方,目前我有一个方法来根据传入的xml对象创建控件。
public static GUIControl CreateControl<T>(T skinXml) where T : XmlControl
{
if (skinXml is XmlButton)
{
return new GUIButton(skinXml);
}
else if (skinXml is XmlGroup)
{
return new GUIGroup(skinXml);
}
....
我有大约30个控件,“if ladder”正在快速增长,我觉得我缺少一个简单的方法来创建控件,而不需要检查xml对象类型,然后创建相应的控件类型。
我无法在Xml对象中添加Type
属性,因为这会创建循环依赖。
对良好工厂方法或新结构布局的任何帮助都很棒
答案 0 :(得分:2)
也许IDictionary<Type, Func<XmlControl, GUIControl>>
会有所帮助。像这样:
private static Dictionary<Type, Func<XmlControl, GUIControl>> _dictionary = new Dictionary<Type, Func<XmlControl, GUIControl>>()
{
{typeof (XmlControlImpl), x => new GUIControl(x)},
{typeof (XmlGroup), x => new GUIGroup(x)},
};
public static GUIControl CreateControl<T>(T skinXml) where T : XmlControl
{
Func<XmlControl, GUIControl> builder;
if (!_dictionary.TryGetValue(typeof(T), out builder))
throw new KeyNotFoundException("");
return builder(skinXml);
}
答案 1 :(得分:2)
好的,我已经找到了一种方法来完成所有的想法和一些反思,不确定它是否是最好的方式,但它工作得很好并且添加一个新的skinnable控件只需要一个新的xml对象和一个属性控制班。
属性类
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class XmlControlTypeAttribute : Attribute
{
protected Type xmlType;
public XmlControlTypeAttribute(Type xmlType)
{
this.xmlType = xmlType;
}
public Type XmlType
{
get { return this.xmlType; }
}
}
控制:
[XmlControlType(typeof(XmlButton))]
public class GUIButton : GUIControl, IActionControl
{
public GUIButton(XmlControl skinXml) : base(skinXml)
{
}
....
}
工厂方法:
public static GUIControl CreateControl2<T>(T skinXml) where T : XmlControl
{
var controlType = Assembly.GetExecutingAssembly().DefinedTypes
.Where(t => t.BaseType == typeof(GUIControl) && t.GetCustomAttribute<XmlControlTypeAttribute>().XmlType.Equals(typeof(T)))
.FirstOrDefault();
return (GUIControl)Activator.CreateInstance(controlType, new[] { skinXml }, null);
}
感谢帮助堆积的所有想法,我会稍微延长这个问题,因为有更好的解决方案比这更好。
答案 2 :(得分:1)
我很想将一个抽象方法添加到XmlControl
:
public abstract class XmlControl
{
[DefaultValue(0)]
public int Width { get; set; }
[DefaultValue(0)]
public int Height { get; set; }
public abstract Type ControlType();
在每个实现中覆盖它,例如:
public class XmlButton : XmlControl
{
public string Label { get; set; }
public override Type ControlType(){ return typeof(GUIButton); }
}
然后在Factory方法中使用反射来构造正确的类:
public static GUIControl CreateControl<T>(T skinXml) where T : XmlControl
{
return (GUIControl)Activator.CreateInstance(skinXml.ControlType(),
new[]{skinXml},null);
}