为什么我的对象仍在使用方法,即使我已经覆盖它?

时间:2011-07-27 13:30:41

标签: c# decorator

可能重复Why my Virtual method is not overriden?

我一直在经历Head First Design Patterns。在旁注中,我开始将本书作为Code Complete 2的先决条件。无论如何,我正在使用Decorator模式(the chapter can actually even be read online)

所以,我有4个班级:

  1. 饮料类 - 摘要
  2. Espresso Class - 继承饮料
  3. BeverageDecorator Class - Abstract
  4. 摩卡类 - 继承饮料Decotrator
  5. 以下是类1,3,4的源代码。

    饮料类:

        public abstract class Beverage
    {
        public Beverage()
        {
            Description = "Unknown Beverage";
        }
    
        public String getDescription()
        {
            return Description;
        }
    
        public abstract double cost();
    
        public String Description { get; set; }
    
    }
    

    BeverageDecorator类:

        public abstract class BeverageDecorator : Beverage
    {
        public new abstract String getDescription();
    }
    

    摩卡课程:

        public class Mocha : BeverageDecorator
    {
        Beverage beverage;
    
        public Mocha(Beverage beverage)
        {
            this.beverage = beverage;
        }
    
        public override string getDescription()
        {
            return beverage.Description + ", Mocha";
        }
    
        public override double cost()
        {
            return beverage.cost() + .20;
        }
    }
    

    所以他们非常直截了当。然后,当我将此代码放入Main()方法时,我不断收到“Unknown Beverage”描述。

            static void Main(string[] args)
        {
    
            Beverage beverage = new Espresso();
            beverage = new Mocha(beverage);
            Console.WriteLine(beverage.Description +
                " $" + beverage.cost());
    
            Console.Read();
    
        }
    

    Mocha 从它继承的类 - Beverage Decorator - 转到上面的类 - Beverage Class。即使我在Beverage Decorator中有方法,我也会覆盖它。为什么会这样?我知道它与抽象类有关,但我似乎无法弄明白。

3 个答案:

答案 0 :(得分:5)

你没有真正地覆盖它。您已使用new运算符隐藏其下方的成员。该运算符的一个问题是,如果调用者使用对包含稍后隐藏的成员的类型的引用,则它会绕过隐藏。在您的情况下,当您使用Beverage并期望看到被覆盖的结果时:

Beverage beverage = new Espresso();        
beverage = new Mocha(beverage);        
Console.WriteLine(beverage.Description + " $" + beverage.cost());

要覆盖某些内容,需要virtualabstract,并且覆盖成员需要使用override。您的成员不是抽象的或虚拟的,在您的派生类中,您new string getDescription不是override string getdescription

因此,当您与Beverage交谈时,代码会忽略BeverageDecorator中的隐藏。

关于装饰器模式的更大讨论,装饰类不需要继承它所装饰的东西。通常通过将装饰类作为构造参数来完成。如果你需要装饰和一些多态性,可以考虑使用一个接口:

interface ICommonStuff
{
    string getDescription();
}

public class Beverage : ICommonStuff { }

public class BeverageDecorator : ICommonStuff
{
    public BeverageDecorator(Beverage b) { }
}

然而,你真的需要装饰吗?这是我在节日期间经常问的事情......

答案 1 :(得分:2)

嗯,有两个问题。首先,看起来您的Description属性应该调用getDescription而不是相反。然后,getDescription类需要虚拟BeverageBeverageDecorator重写而不是隐藏

您的代码看起来像C#和Java的混合物并没有帮助。例如,你真的需要一个Description属性一个getDescription方法吗?不可否认,覆盖半个属性有点棘手(至少,我总是对确切的规则感到困惑)但是在C#代码中使用camelCased名称​​肯定是奇怪。

这是一个替代实现(没有装饰器类 - 目前还不清楚它是如何帮助的):

using System;

public abstract class Beverage
{
    public Beverage()
    {
        Description = "Unknown Beverage";
    }

    private string description;

    public virtual string Description
    {
        get { return description; }
        set { description = value; }
    }
}

public class Espresso : Beverage
{
    public Espresso()
    {
        Description = "Espresso";
    }
}

public class Mocha : Beverage
{
    private readonly Beverage beverage;

    public Mocha(Beverage beverage)
    {
        this.beverage = beverage;
    }

    public override string Description
    {
        get { return beverage.Description + ", Mocha"; }
        set { /* Ignored */ }
    }
}

public class Test
{
    static void Main()
    {
        Beverage espresso = new Espresso();
        Beverage mocha = new Mocha(espresso);
        Console.WriteLine(mocha.Description); // Prints Espresso, Mocha
    }
}

答案 2 :(得分:2)

  

public new abstract String getDescription();

这是方法覆盖,它是与基类中的getDescription方法无关的新方法。

Beverage.getDescription无法覆盖,因为它不是虚拟的。相反地​​声明它:

public abstract String getDescription();

或者那样:

public virtual String getDescription()
{
    return Description;
}