这是动态类的情况吗?
本文关键字:情况 动态 | 更新日期: 2023-09-27 18:09:51
我甚至不确定关于这个问题应该搜索什么,所以我想我应该把它贴在这里。
假设我有一堆接口,比如…
/// <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:如何使用Decorator?
从我看到的装饰器,你可以扩展一个对象的功能。那很酷。但是,您必须事先知道如何扩展该功能。
考虑我的代码库如上所述,我想使用decorator。
我想说:
// 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))
你不能再做公主。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,我就可以安全地向下转换。我觉得可能有一种使用泛型来避免强制类型转换的方法。
当调用As时,任何实现IMasterInterface的具体类都可以简单地返回它们自己。
编辑3:感谢大家的评论。我很高兴我张贴了我对模式的无知;D谢谢你的澄清!我爱这个网站和所有你可爱的人在那里!!
尝试查看Decorator设计模式。据我所知,它是针对你所想到的那种情况的,即对象可以包含从一组属性中提取的混合属性集。在Decorator模型中,每个属性都是自己的一个类,您可以有效地动态连接这些类,以创建具有所需属性的对象。
要实现过滤,您需要某种类型的迭代器来遍历decorator链,以查看您要测试的对象是否包含了您要寻找的decorator。
我没有在c#中使用过Decorator,只有在c++中使用过,但我发现它是一种非常有用和灵活的前进方式。如果你发现自己创造了更多&更专业的类,代表"属性"类的交叉点,那么我认为Decorator可能会很有帮助。
请参阅c#中的装饰器设计模式以获取有关此模式的信息。(并购买并阅读GoF设计模式书!)
根据您的更新,我看到您似乎不理解装饰器模式。
我不知道这是否是最好的方式去,如果你没有任何不同的行为和你的接口是静态的(IenjoyLookingAtGoods, IConsumeGoods等),你可以继续和实现这些属性在你的抽象类型,只是通过设置它们创建新的实例。
装饰符应该是这样的
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 || 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 || instance.Is<T>();
}
}
如果你想要得到同时实现两者的东西你需要这样做:
IMasterInterface princess = new MasterClass() //whatever your concrete type is named
princess = new ConsumesGoodsDecorator(new EnjoyLookingDecorator(princess))
var b = princess.Is<IEnjoysLookingAtGoods>()
编辑-你可以像这样修改它:
T As<T>()
{
return this is T ? this : instance.As<T>(); /*be careful here, the implementation in the concrete class should return null if he is not a T*/
}
/*continuing the example above*/
var consumer = princess.As<IConsumesGoods>(); //this is good
var producer = princess.As<IProducesGoods>(); //this will return null
,但这是讨厌的,我读你的问题最多,似乎这些接口没有意义。你根本没有增加行为。为什么不有一个类实现IMasterInterface,并有4个属性与不同的接口(组合),如果你不希望公主有IProduceGoods然后设置为空。没有上下文仍然很难理解
HTH
我不喜欢IMasterInterface这个概念,但假设您只是在使用一个抽象的术语来表达这个问题-我可以看到过去。我对你例子中的用法也有一点小小的怀疑:
IMasterInterface princess = MyFactory.Create(IEnjoyLookingAtGoods, IEnjoyLookingAtGoodsParameters, IConsumeGoods, IConsumeGoodsParameters)
/// This should be true
((princess is IEnjoyLookingAtGoods) && (princess is IConsumeGoods))
难道"公主"不应该是"像洋娃娃和消费品一样的东西"吗?
除此之外,我认为对实现的接口类型进行过滤的方法是好的。
这是一个很好的方法。坦率地说,我不觉得有什么问题。接口只是接口——它们只提供了一种描述一组公共成员的方法。问题是你的问题太笼统了,很难理解你想要达到的目的。
接受接口的工厂方法非常奇怪。例如,我们有以下代码:
public class A : IFoo { }
public class B : IFoo { }
var x = MyFactory.Create(IFoo);
工厂会创造什么?A还是B的实例?
无论如何,我认为我能想到的最好的建议是:不要想太多。回答关于工厂的问题,您可以使用反射和/或原型模式来完成,但前提是接口的组合是唯一的。如果您有多个可以满足所请求接口列表的具体类(例如,类princess和Prince),那么工厂将无法知道该创建哪个。
如果没有具体的类,而你真的试图在运行时创建/组合/等对象,那么这是一个不同的颜色的马。您可能需要一个公共基类(或者可能在您的主接口中支持)来协助使用(如另一位海报所建议的)装饰器方法,或者使用facet类型模式。