【发布时间】:2011-11-26 20:55:31
【问题描述】:
关于这个问题我什至不确定要搜索什么,所以我想我会在这里发布。
假设我有一堆接口,比如...
/// <summary>
/// All interesting classes will implement this interface
/// </summary>
interface IMasterInterface {}
/// <summary>
/// Interface to represent someone that creates / produces goods
/// </summary>
interface IProduceGoods : IMasterInterface { int Prop1 {get;} }
/// <summary>
/// Interface to represent someone that buys / consumes goods
/// </summary>
interface IConsumeGoods : IMasterInterface { int Prop2 {get;} }
/// <summary>
/// Interface to represent someone that stores goods
/// </summary>
interface IStoreGoods : IMasterInterface { double Prop3 {get;} string name {get;}}
/// <summary>
/// Interface to represent someone that enjoys looking at goods
/// </summary>
interface IEnjoyLookingAtGoods : IMasterInterface { int Prop4 {get;} DateTime Prop5 {get;} }
现在,我知道我今天想要一些组合,例如:
/// <summary>
/// Class to represent a farm which grows and stores crops
/// </summary>
class Farm : IProduceGoods, IStoreGoods {/*...*/}
/// <summary>
/// Class to represent a merchant who buys goods and stores them
/// </summary>
class Merchant : IConsumeGoods, IStoreGoods {/*...*/}
/// <summary>
/// Window Shopper represents someone who doesn't buy anything and only looks
/// </summary>
class WindowShopper : IEnjoyLookingAtGoods{ /*...*/ }
现在我很高兴我有几节课,但我想,明天还有一个有人从商家那里购买的课程不是很好,所以我会去我的代码和添加
/// <summary>
/// Princesses have lots of money to buy stuff and lots of time to look at stuff
/// </summary>
class Princess : IEnjoyLookingAtGoods, IConsumeGoods {/*...*/}
现在,我认为我不应该这样做......
我想做的是有一个工厂(或类似)的东西并说:
IMasterInterface princess = MyFactory.Create(IEnjoyLookingAtGoods, IEnjoyLookingAtGoodsParameters, IConsumeGoods, IConsumeGoodsParameters)
/// This should be true
((princess is IEnjoyLookingAtGoods) && (princess is IConsumeGoods))
本质上,我想告诉工厂使用哪些接口来构造对象。我有包含 IMasterInterface 列表的容器
/// <summary>
/// My container class for interesting objects
/// </summary>
class InterestingObjectContainer
{ public ReadOnlyCollection<IMasterInterface> InterestingObjects {get;} }
现在,问题的关键就在这里。让所有有趣的类实现 IMasterInterface 的原因是能够拥有一个 List 并使用更具体的接口作为过滤器。也许下面的内容会更清楚:
/// <summary>
/// I want to see the net population of producers and get there total production
/// </summary>
class ProducerProductionCalculator
{
// THIS IS WHERE THE MEAT OF THE QUESTION RESIDES!
ProductionResults Calculate(InterestingObjectContainer interestingObject)
{
List<IProduceGoods> producers = interestingObject.InterestingObjects.OfType<IProduceGoods>(); // Perhaps more interest LINQ
return DoSomethingWithListToAggregate(producers);
}
}
通过过滤到更具体的接口,我现在可以依靠传递给的所有对象 DoSomethingWithListToAggregate(ICollection 生产者) 拥有 IProduceGoods 类的方法/属性。
我曾考虑使用字典和字符串属性查找来实现这一点,但感觉我可以通过这种方式编写更强类型的代码,并确保某个地方的简单拼写错误不会搞砸一切。
反正我猜总结是:
这是在对象上实现变量属性的糟糕方法吗?如果是这样,那会更好。如果没有,有没有办法像我在上面解释的那样在工厂中创建对象?
编辑:
我认为这样做的想法有些不错,这很酷。我想知道如何创建一个工厂,该工厂接受一个只有属性的接口的参数,并且这些属性只有 getter(我认为这是一个重要的点)以及属性的属性值,并返回一个实现接口并拥有所有定义的属性。
例如,
/// <summary>
/// Factory to create any combination of properties
/// </summary>
class FactoryForInterestingObjects
{
public static IMasterInterface Create(
List<KeyValuePair</*what goes here is the interface that I want to use,
what goes here are the parameter values that
should be returned by the getter */>> );
}
我会将所有接口及其参数值传递给工厂,它会创建一些实现这些接口并具有这些值的类。希望这更清楚一点?
编辑 2:如何使用装饰器?
根据我对装饰器的了解,您可以扩展对象的功能。这很酷。但是,您必须提前知道如何扩展该功能。你不能随意这样做。
考虑到我的代码库如上,我想使用装饰器。
我会说:
// Edited to be correct
class EnjoyLookingDecorator : IEnjoyLookingAtGoods
{
private IMasterInterface instance;
public EnjoyLookingDecorator(IMasterInterface wrappedObject)
{ this.instance = wrapped Object;}
#region Implementation of IEnjoyLookingAtGoods
/*...*/
#endregion
}
编辑 4:
我仍然认为这行不通。在您的示例中,我丢失了包含的类接口,我必须将其重定向。例如,
class EnjoyLookingDecorator : IEnjoyLookingAtGoods
{
private IMasterInterface instance;
public EnjoyLookingDecorator(IMasterInterface concrete)
{ this.instance = concrete;}
#region Implementation of IEnjoyLookingAtGoods here
/*...*/
#endregion
bool Is<T>() //this should be in the IMasterInterface
{
return this is T or instance is T;
}
}
class ConsumesGoodsDecorator : IConsumeGoods
{
private IMasterInterface instance;
public ConsumesGoodsDecorator (IMasterInterface concrete)
{ this.instance = concrete;}
#region Implementation of IConsumeGoods here
/*...*/
#endregion
bool Is<T>()
{
return this is T or instance is T;
}
}
所以当你 d
IMasterInterface princess = new MasterClass() //whatever your concrete type is named
princess = new ConsumesGoodsDecorator(new EnjoyLookingDecorator(princess))
你不能再做 Princess.PropertyOnIEnjoyLookingDecoratorInterface 你失去了所有这些属性。这不是我想要的。保留属性的唯一方法是重定向
class ConsumesGoodsDecorator : IConsumeGoods, IEnjoyLookingAtGoods
{
private IMasterInterface instance;
public ConsumesGoodsDecorator (IMasterInterface concrete)
{ this.instance = concrete;}
#region Implementation of IConsumeGoods here
/*...*/
#endregion
#region Redirect all the IEnjoyLookingAtGoods Property Getters to instance
/* ... */
#endregion
bool Is<T>()
{
return this is T or instance is T;
}
}
通过重定向,我们必须实现接口。然后组合必须都有代码,这是我试图避免的。我对接口的组合没有限制。
编辑 5:
也许我的问题还不清楚。想象一下上面填充了属性的接口。
如果工厂可以这样做:
/// <summary>
/// Factory to create any combination of properties
/// </summary>
class FactoryForInterestingObjects
{
public static IMasterInterface Create(
List<KeyValuePair<Type t, ArgSet customArguments>> interfaces))
{
object baseObject;
foreach(KeyValuePair<Type, ArgSet> interface in interfaces)
{
AddInterface(interface, object);
}
}
private static void AddInterface(KeyValuePair<Type, ArgSet> interface, ArgSet arguments)
{
// Delegate this to someone else
if(interface.Key is typeof(IProduceGoods))
{
IProduceGoodsExtensions.AddInterface(o, interface.value);
}
}
}
public static class IProduceGoodsExtensions
{
public static void AddInterface(object o, ArgSet arguments)
{
// do something to object to make it implement IProductGoods
// and make all the getters return the arguments passed in ArgSet
}
}
我意识到这不是它的实际工作方式,而是说明了我想要表达的观点。我希望该对象实现接口的动态组合并具有设置器的默认值。
即使我可以做一些事情,比如让工厂编写一个包含代码的文本文件:
/// <summary>
/// Auto Generated by Factory to create a new type on the fly
/// </summary>
class ClassImplementingIProduceGoodsAndIEnjoyLookingAtGoods : IProduceGoods, IEnjoyLookingAtGoods
{
// From IProduceGoods
public int Prop1 {get; private set;}
// From IEnjoyLookingAtGoods
public int Prop4 {get; private set;}
public DateTime Prop5 {get; private set;}
public ClassImplementingIProduceGoodsAndIEnjoyLookingAtGoods(int prop1, int Prop4 , DateTime Prop5)
{
this.Prop1 = prop1; this.Prop4 = Prop4; this.Prop5 = Prop5;
}
}
然后编译该类并以某种方式允许我创建它的实例。这就是我要找的。希望这更有意义。
编辑 6:
这是我可能会采用的解决方案,因为我目前没有看到替代方案。
//Update Master Interface
interface IMasterInterface
{
bool Is(Type t);
IMasterInterface As(Type t);
}
/// <summary>
/// Class to build up a final object
/// </summary>
class CompositionObject : IMasterInterface
{
ICollection<IMasterInterface> parts;
CompositionObject(IMasterInterface object){ parts = new List<IMasterInterface(object);}
bool Is(Type t)
{
foreach(IMasterInterface part in parts)
{ if (part is t) return true; // not sure on this off top of head
}
return false;
}
IMasterInterface As(Type t)
{
foreach(IMasterInterface part in parts)
{ if(part is t) return part; }
}
bool Add(IMasterInterface interface)
{ this.Is(typeof(interface)) return false; // don't add again
this.parts.Add(interface) }
}
现在我的工厂可以只返回这些组合对象,只要调用了 As,我就可以安全地向下转换。我觉得可能有一种方法可以使用泛型来避免强制转换。
任何实现 IMasterInterface 的具体类都可以在调用 As 时简单地返回自己。
编辑 3:
感谢大家的cmets。我很高兴我发布了我对模式的无知;D 感谢您的澄清!我喜欢这个网站和所有可爱的人!
【问题讨论】:
-
为什么你不能用你提到的方法结束
InterestingObjects.OfType<IProduceGoods>()? -
@sll:我不知道怎么做工厂。这就是问题所在。或者如果这甚至是一个好方法。
-
您希望所有这些接口之间的行为有何不同?除了吸气剂?
-
几乎是吸气剂。有一些特殊对象将直接在代码中实现,它们的行为与 getter / setter 不同。工厂可以根据传递的参数查找这些。我会尝试进一步解释。
-
看来你想要的是拥有一种单一类型的不同实例,如果你不打算有依赖于它的行为,你不需要用接口标记东西,但我没有你这么多的上下文,所以我可能遗漏了其他东西
标签: c# class dynamic properties factory