【发布时间】:2014-08-23 02:42:47
【问题描述】:
我有一种工厂模式看起来像这样的情况:
enum Food {
Cake,
Cookies,
Milk,
CannedBeans
}
public static class FoodMetaDataFactory{
public static IFood GetMetaData(Food foodType){ //takes a food enum value as a parameter
switch(foodType){
case Food.Milk:
return new MilkMetaData();
case Food.CannedBeans:
return new CannedBeansMetaData();
case Food.Cookies:
return new CookiesMetaData();
case Food.Cake:
return new CakeMetaData();
}
}
}
但是,我宁愿有像这样的声明性模式:
enum Food {
[FoodMetaDataAttribute(typeof(CakeMetaData))]
Cake,
[FoodMetaDataAttribute(typeof(CookiesMetaData))]
Cookies,
[FoodMetaDataAttribute(typeof(MilkMetaData))]
Milk,
[FoodMetaDataAttribute(typeof(CannedBeansMetaData))]
CannedBeans
}
public static class FoodMetaDataFactory{
public static IFood GetMetaData(Food foodType){ //takes a food enum value as a parameter
//reflectively retrieve FoodMetaDataAttribute
Type enumType = typeof(Food);
var memInfo = enumType.GetMember(foodType.ToString());
//assume one item returned
var foodMetaDataAttributes = memInfo[0].GetCustomAttributes(typeof(FoodMetaDataAttribute),
false);
// now access the property telling us the concrete type of the metadata class(this is the type passed in the attribute's declaration
Type targetType = ((FoodMetaDataAttribute)foodMetaDataAttributes[0]).MetaDataProviderType;
//not done yet, now we need to reflectively instantiate targetType, something like this
ConstructorInfo ctor = targetType.GetConstructor(new[] { });
//invoke the constructor, returning concrete instance such as CakeMetaData
return ctor.Invoke(new object[] {}) as IFood;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class FoodMetaDataAttribute : Attribute
{
public FoodMetaDataAttribute(Type metaDataProviderType){
MetaDataProviderType = metaDataProviderType;
}
public Type MetaDataProviderType { get; set; }
}
我喜欢这个,因为任何向枚举添加新值的人都清楚他们需要一个元数据类并在属性中声明它。这个 IMO 比必须记住在工厂修改开关盒要好。
起初看起来很简单,直到我开始考虑 GetMetaData 的实现,它必须反射地检索属性、typeof 参数,然后反射地实例化 MetaData 类。 我没有创建属性类的经验,所以这个问题的主要驱动力是希望也许有一种更简单的方法可以用属性来完成。如果属性类没有那么多限制,例如在使用泛型类型时,我会以我喜欢的方式完成此操作,并具有一定的编译时安全性。
这个提议的解决方案没有编译时安全性。您可以将类型传递给不实现 IFood 的属性,这是 MetaData 类(如 MilkMetaData)的最低要求。如果属性允许泛型类型参数,我会使用它而不是 typeof 并且可以应用 where T:IFood
有没有更好的方法来利用属性来完成从枚举值到具体类的映射?
【问题讨论】:
-
这道题需要类图
-
经典类图描述了继承关系。他们甚至没有描述组合,也没有描述“这段代码调用这个类”(用 UML 术语来说,这是序列图的工作)。我不确定类图中会显示什么,因为这里没有继承。 你能指出你在哪里感到困惑,我会尝试改进这个问题吗?
-
我不明白其中涉及哪些具体类或实例化什么。你说这里没有继承,但多态性可能是解决问题的一个非常简单的方法。
-
您显然有大量的数据和行为附加到每种食物种类。为什么不将
Food设为具有私有构造函数的类并为每种类型(例如牛奶、蛋糕等)创建一个公共静态属性。然后它们将具有枚举的“感觉”,但可以具有其他属性/方法。 -
这给我一种代码味道,如果特定的枚举值和元数据紧密耦合,只需重构为类。
标签: c#