Possible Repeat: Why my Virtual method is not overriden?
I've been going through the Head First Design Patterns. On a side note, I started this book as a prerequisite to Code Complete 2. Anyway, I'm working with the Decorator pattern (the chapter can actually even be read online).
So, I have 4 classes:
Here is the source code for classes 1, 3, 4.
Beverage Class:
public abstract class Beverage
{
public Beverage()
{
Description = "Unknown Beverage";
}
public String getDescription()
{
return Description;
}
public abstract double cost();
public String Description { get; set; }
}
BeverageDecorator Class:
public abstract class BeverageDecorator : Beverage
{
public new abstract String getDescription();
}
Mocha Class:
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;
}
}
So they are pretty straight-forward. Then when I put this code in the Main() method I keep getting an "Unknown Beverage" description.
static void Main(string[] args)
{
Beverage beverage = new Espresso();
beverage = new Mocha(beverage);
Console.WriteLine(beverage.Description +
" $" + beverage.cost());
Console.Read();
}
Mocha goes from the class it inherits - Beverage Decorator - to the class above that - Beverage Class. Even though I have the method in the Beverage Decorator and I override it. Why is this happening? I know it has something to do with being abstract classes but I just can't seem to figure it out.
You have not overridden it truely. You have used the new
operator to hide a member below it. The one problem with that operator is that if the caller uses a reference to the type that holds the member that is hidden later on, it bypasses the hiding. In your case, it is when you use Beverage
and expect to see the overridden result:
Beverage beverage = new Espresso();
beverage = new Mocha(beverage);
Console.WriteLine(beverage.Description + " $" + beverage.cost());
To override something, that something needs to be virtual
or abstract
and the overriding member needs to use override
. Your member isn't abstract or virtual, and in your derived class you have new string getDescription
not override string getdescription
.
So in your code when you talk to Beverage
it ignores the hiding done in BeverageDecorator
.
A bigger discussion on the decorator pattern, the decorating class doesn't need to inherit from what it decorates. Usually it is done by taking the decorated class as a construction parameter. If you need decoration and also some polymorphism, consider using an interface in conjunction with it:
interface ICommonStuff
{
string getDescription();
}
public class Beverage : ICommonStuff { }
public class BeverageDecorator : ICommonStuff
{
public BeverageDecorator(Beverage b) { }
}
But then, do you really need decoration? This is something I ask frequently around the holidays...
Well, there are two problems. Firstly, it looks like your Description
property should call getDescription
rather than the other way round. And then getDescription
needs to be virtual in the Beverage
class and overridden in BeverageDecorator
rather than hidden.
It doesn't help that your code looks like a mixture of C# and Java. For example, do you really need a Description
property and a getDescription
method? Admittedly it's slightly tricky to override half a property (at least, I always get confused about the exact rules) but it's definitely odd to have camelCased names in C# code.
Here's an alternative implementation (no decorator class - it's not clear how that was meant to help):
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With