【问题标题】:Why is my Object still using a method even though I have overriden it?为什么我的对象仍然使用一个方法,即使我已经覆盖了它?
【发布时间】:2011-07-27 13:30:41
【问题描述】:

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

我一直在研究 Head First 设计模式。顺便说一句,我开始这本书是作为 Code Complete 2 的先决条件。无论如何,我正在使用装饰器模式 (the chapter can actually even be read online).

所以,我有 4 个课程:

  1. 饮料类 - 摘要
  2. Espresso 类 - 继承饮料
  3. BeverageDecorator 类 - 抽象
  4. 摩卡类-继承饮料装饰

这是 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() 方法时,我不断收到“未知饮料”的描述。

        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 中有方法并且我覆盖了它。为什么会这样?我知道这与抽象类有关,但我似乎无法弄清楚。

【问题讨论】:

标签: c# decorator


【解决方案1】:

你没有真正覆盖它。您已使用 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) { }
}

但是,你真的需要装饰吗?这是我在假期经常问的问题......

【讨论】:

  • 我应该很快看到我不能覆盖没有声明为抽象或虚拟的方法。我对编程,尤其是 C# 还是很陌生。我只是使用书中的代码和技术,并将它们从 Java 转换为 C#。我也许应该在本书的论坛上提问,但是,我喜欢 StackOverflow!这本书可能不是最好的,但这就是为什么我只用它来介绍这些模式。
  • @Adam Beck head first design patterns 是一本很好的书。但是,如果您也是 C# 新手,我建议您也阅读一些这方面的书籍。你选择了正确的地方来提问 - 你不会从其他任何地方得到更快的回应:-)
【解决方案2】:

嗯,有两个问题。首先,看起来您的 Description 属性应该调用 getDescription 而不是相反。然后getDescription 需要在Beverage 类中是虚拟的,并且在BeverageDecorator覆盖 而不是隐藏

您的代码看起来像是 C# 和 Java 的混合体,这无济于事。例如,您真的需要 Description 属性 getDescription 方法吗?诚然,重写半个属性有点棘手(至少,我总是对确切的规则感到困惑),但在 C# 代码中使用驼峰式命名是绝对奇怪的。

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

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
    }
}

【讨论】:

  • 您发现我对 C# 语言还很陌生,事实上我使用的书是用 Java 编写的。因此,我只是自我解释/翻译了他们在书中给我的代码。这虽然有效,但我明白了为什么(以及为什么我的没有)。非常感谢。
【解决方案3】:

public new abstract String getDescription();

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

Beverage.getDescription 不能被覆盖,因为它不是虚拟的。改为这样声明:

public abstract String getDescription();

或类似:

public virtual String getDescription()
{
    return Description;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-10
    相关资源
    最近更新 更多