这是动态类的情况吗?

本文关键字:情况 动态 | 更新日期: 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类型模式。

相关文章: