【问题标题】:Which design pattern allows to get this architecture哪种设计模式允许获得这种架构
【发布时间】:2014-06-09 11:11:37
【问题描述】:

我有以下物品:

  • 公式
  • 库存
  • 计数器
  • 等等……

所有这些对象都称为指标并具有共同的属性(Id、Name、Value...)。 每个实体都有自己的属性:

  • 公式:FormulaExpression、FormulaCode、OperandsList ...
  • 库存:StockValue、StockLimit...
  • 计数器:CounterIndex...
  • 等等...

所以从逻辑上讲,我必须创建包含公共属性的指标类,并且我必须为每个实体创建一个继承自指标的类。

公式是一种特殊的指标,可以包含任何类型的指标。公式的指标被命名为操作数。

操作数对象具有以下属性: 操作数Id、操作数代码、操作数索引

当我想列出公式操作数时,我想获取从指标、操作数和实体类型继承的对象(例如,创建一个具有指标属性、操作数属性和股票属性的对象)

哪种设计模式或哪种架构允许我有这种行为?


解释更多问题

实体(FormulastockCounter..)是Indicators,而OperandsOperands 也不一定是Indicators。对象Indicator 是实体的原始类型,我们可以创建一个Indicator,然后将其修饰为Formula,然后在将其添加到另一个Formula 时将其修饰为Operand

【问题讨论】:

  • Formula 指标能否在其操作数列表中包含另一个 Formula 指标?
  • 是的,公式可以包含任何类型的指标,甚至公式类型
  • 请记住,说“设计模式允许人们获得架构”是没有任何意义的。lol
  • 那么您是否找到了实现所需的方法?
  • dogiordano 给出的解决方案似乎是正确的,我正在尝试通过删除泛型类型来改进它。

标签: c# oop design-patterns inheritance architecture


【解决方案1】:

最好的方法是使用一个expando对象,每个操作数使用多态调度填充。 expando 对象可让您添加自定义属性,多态分派可让您针对操作数更改关闭代码。

您将从使用包含基本元素的操作数的基类开始

public abstract class Operand
{
    public int Id { get; set; }
    public string Name { get; set; }

    public dynamic BuildObject()
    {
        dynamic o = new ExpandoObject();
        o.Id = Id;
        o.Name = Name;
        AddPropertiesToObject(o);
        return o;
    }

    protected internal abstract void AddPropertiesToObject(dynamic o);
}

然后添加一个新的操作数类型非常容易,因为您可以独立控制要添加的内容:

public class Stock : Operand
{
    public double StockValue { get; set; }

    protected internal override void AddPropertiesToObject(dynamic o)
    {
        // I decided to ignore the base class Id and Name
        // adding them would be trivial, but may not be what you need since 
        // it would overwrite the base values...
        // To add them you would have to wrap this virtual method call with
        // a call to a function doing the insertion in the base class 
        o.StockValue = StockValue;
    }
}

Formula 对象将简单地迭代包含的操作数并依次调用它们的 AddPropertiesToObject(当然它也可以添加自己的数据,但在示例中我没有包含任何数据)

public class Formula : Operand
{
    public List<Operand> InnerOperands { get; set; }

    protected internal override void AddPropertiesToObject(dynamic o)
    {
        foreach (var op in InnerOperands)
        {
            op.AddPropertiesToObject(o);
        }
    }
}

【讨论】:

  • 感谢您的回答,但项目正在框架 3.5 下运行 :(
  • 原理还是可以调整的。您可以将值存储在键值字典中,或者以任何您想要的方式。重要的是,您无需知道操作数的类型即可调用适用于您要返回的对象的方法
  • 据我了解您的解决方案,实体从 Operand 对象继承,并使用 AddProperitiesToObject 方法从数据库中获取属性值。现在的问题是实体(FormulastockCounter..)是Indicators,而OperandsOperands 也不一定是Indicators。对象Indicator 是实体的原始类型,我们可以创建一个Indicator,然后将其修饰为Formula,然后在将其添加到另一个Formula 时将其修饰为Operand。所以从Operand继承并不是描述对象的最佳方式。
  • 我误解了基类是什么,但您可以通过将Operand 基类重命名为Indicator 基类来转换我的建议。您将拥有从 Indicator 继承的 Operand,并将在正确级别插入具体类
【解决方案2】:

我在这里发布的内容可能看起来很多代码,但实际上非常简单。

大部分属性和构造函数都是为了简化 main 函数中的脚本。

基本概念是为操作数创建一个Generic Class,其中包含对创建它的基础Indicator 对象的引用。

在一个空项目中测试这段代码,从输出中很容易理解。

class Indicator{
    // Common properties
}
class Counter : Indicator{
    public int CounterIndex;
    public Counter(int cI){
        CounterIndex = cI;
    }
    public void Print()
    {
        Console.WriteLine("CounterIndex: {0}", CounterIndex);
    }
}
class Operand{
    // Common operand properties
}
class Operand<T> : Operand{
    public T BaseIndicator;
    public Operand(T bI){
        BaseIndicator = bI;
    }
}
class Formula : Indicator{
    public string FormulaExpression;
    public int FormulaCode;
    public List<Operand> OperandsList = new List<Operand>();

    public Formula(string fE, int fC){
        FormulaExpression = fE;
        FormulaCode = fC;
    }

    public void Print ()
    {
        Console.WriteLine ("FormulaExpression: {0}; FormulaCode: {1}",
                           FormulaExpression, FormulaCode);
        if (OperandsList.Count == 0) {
            return;
        }
        Console.WriteLine("Begin Operands: ");
        foreach(Operand o in OperandsList){
            if(o is Operand<Counter>){
                Operand<Counter> cO = o as Operand<Counter>;
                cO.BaseIndicator.Print();
            }else if(o is Operand<Formula>){
                Operand<Formula> fO = o as Operand<Formula>;
                fO.BaseIndicator.Print();
            }else{
                // I'ts a simple Indicator
            }
        }
        Console.WriteLine("End Operands");
    }
}
class MainClass
{
    public static void Main (string[] args)
    {
        Counter c1 = new Counter(2);
        Counter c2 = new Counter(3);
        Formula f1 = new Formula("a + b", 7);
        Formula f2 = new Formula("a * b", 10);

        Formula f = new Formula("a ^ b", 32);
        f.OperandsList.Add(new Operand<Counter>(c1));
        f.OperandsList.Add(new Operand<Formula>(f1));
        f.OperandsList.Add(new Operand<Counter>(c2));
        f.OperandsList.Add(new Operand<Formula>(f2));
        f.Print();
        Console.ReadLine();
    }
}

【讨论】:

  • Operand 是一个具有自身属性(operandId、operandCode、operandIndex)的对象。问题是在运行时对象可以是指标、公式(或股票或...)和操作数。
  • Stock、Counter、Formula 不是必须的操作数,它们只是一个指标,我想把指标装饰成公式或股票,然后再装饰它成为一个操作数。你认为你的方案能解决这个问题吗?
猜你喜欢
  • 2023-03-10
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 2012-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多