【问题标题】:c# object behaviour with polymorphismc# 具有多态性的对象行为
【发布时间】:2015-01-16 19:33:07
【问题描述】:

我正在尝试解决一个让我头疼的涉及多态性的问题。代码是这样的:

public abstract class Base
{
   public int val {get;set;}
   public virtual bool merge(Base obj) { return false; }
}

public class A : Base
{
   public override bool merge(Base obj)
   {
      /* If obj is of type A sum the "val" and return true, otherwise retur false */
   }
}

public class B : Base
{
   public override bool merge(Base obj)
   {
      /* If obj is of type B sum the "val" and return true, otherwise retur false */
   }
}

public class Composite
{
   List<Base> objects;
   public void addObject(Base obj)
   {
      foreach(Base b in this.objects)
      {
          if (b.merge(obj))
              return;
      }

      this.objects.Add(obj);
   }
}

我想要实现的是,在将 obj 添加到 Composite 类时,使要添加的对象“合并”到具有相同类型的对象,否则将其添加到列表中。我想在不使用“if”语句或检查对象类型的情况下对这种行为进行编码
编辑:将对象添加到 Composite 类时,我希望使用要添加的对象的值来更新 Composite 中的对象。所以如果我有:

Composite C = new Composite();
C.addObject(new A(2));
C.addObject(new B(10));
// here C has { (A,2) , (B,10) }
C.addObject(new A(1));
// here C should have { (A,3) , (B,10) }

到目前为止,我想出了一个稍微复杂的解决方案,它不涉及“if”语句:

public abstract class Base
{
   public int val {get;set;}
   public virtual bool tryMerge(Base obj) { return false; }
   public virtual bool mergeA(A obj)  { return false; }
   public virtual bool mergeB(B obj)  { return false; }
}

public class A : Base
{
   public override bool tryMerge(Base obj)
   {
      return obj.mergeA(this);
   }

   public override bool mergeA(A obj)
   {
      obj.val += this.val;
      return true;
   }
}

public class B : Base
{
   public override bool merge(Base obj)
   {
      return obj.mergeB(this);
   }

   public override bool mergeB(B obj)
   {
      obj.val += this.val;
      return true;
   }
}

public class Composite
{
   List<Base> objects;
   public void addObject(Base obj)
   {
      foreach(Base b in this.objects)
      {
          if (b.tryMerge(obj))
              return;
      }

      this.objects.Add(obj);
   }
}

有什么建议吗? 提前致谢!

【问题讨论】:

  • 目前尚不清楚val 值的总和会发生什么情况。应该将其分配给对象本身的val 属性、参数对象,还是两者兼而有之?
  • 另外,mergeAmergeB 方法不应退出。基础中应该只有 merge 方法,它在 AB 中都被覆盖,如上面的示例代码所示。
  • 看来您要求的是更好的算法,那么您应该在codereview.stackexchange.com提出您的问题
  • 当您调用 addObject(obj) 时,Composite.objects 中与您的 obj 类型匹配的第一个项目将被合并,而 Coposite 类中具有相似类型的其余项目将被忽略。你知道吗?
  • CarbineCoder 我知道这一点,但是对于扩展 Base 的每种类型,Composite 应该只有一个对象。 ;)

标签: c# .net oop polymorphism


【解决方案1】:

您的方法还不错,尽管您应该将 mergeAmergeB 函数声明为受保护的,因为它们不应被公开,但您需要在调用 mergeAmergeB 之前进行一些类型检查和强制转换。

另一种方法是在基类中定义 this(不重载任何这些函数):

public abstract class Base
{
   public int val {get;set;}
   public bool merge(Base obj) { 
     if(obj.GetType() != this.GetType())
       return false;

     this.val += obj.val;

     return true;
   }
}

【讨论】:

  • 感谢乔安沃!我考虑过这一点,事实上,这就是我所做的。我只是想尽量避免'if'和GetType();)至于'受保护',如果我将mergeA和mergeB声明为'受保护',我将无法从派生类中调用它们,因为我'我在“Base”类型的对象上调用它们
  • 嗨,ANVerona,无论如何,您可能需要if 语句进行类型检查。顺便说一句,派生类可以看到protected 基类中的函数和成员(它们不像private)。
  • 如果它们受到保护,则不能从 Base 类型的 obj 上的派生类中调用它们。编译器说:无法通过“Base”类型的限定符访问受保护的成员“Base.mergeA(A)”;限定符必须是“A”类型(或派生自它)
【解决方案2】:
public abstract class Base
    {
        public int val { get; set; }

        public abstract bool Merge<T>(T obj) where T:Base;
    }

    public class A : Base
    {
        public A(int val)
        {
            this.val = val;
        }

        public override bool Merge<A>(A obj)
        {
            if (obj.GetType() != GetType())
                return false;

            val += obj.val;
            return true;
        }
    }

    public class B : Base
    {
        public B(int val)
        {
            this.val = val;
        }

        public override bool Merge<B>(B obj)
        {
            if (obj.GetType() != GetType())
                return false;

            val += obj.val;
            return true;
        }
    }

    public class Composite
    {
        List<Base> objects = new List<Base>();

        public void addObject(Base obj)
        {
            foreach (Base b in this.objects)
            {
                if (b.Merge(obj))
                    return;
            }

            this.objects.Add(obj);
        }
    }

【讨论】:

  • 感谢 Low Flying Pelican,但是使用“GetType”方法,您只需在基类中编写一个 Merge 方法,它就可以完美运行,无需重复代码和泛型类型。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 2017-03-28
相关资源
最近更新 更多