0

I'm working through the Head First Design Patterns book and am currently on the Decorator Pattern chapter. Since the book examples are written in Java, I'm adapting the, to C# as I go.

This example simulates a coffee shop ordering system. There is an abstract base class for Beverage and subclasses for specific beverages (ex: Espresso). The decorator classes are used to add condiments and drink modifications. There is an abstract class CondimentDecorator that derives from Beverage and then subclasses like Mocha for the individual decorators. Gist with all files: https://gist.github.com/anonymous/67e4fe5fe0477d34b24125f741ad0b3a

My question - in the base Beverage class, the description string is set to "Unknown beverage". The constructor for a specific drink sets this to the drink name - so if I use:

Beverage espresso = new Espresso();
Console.WriteLine($"{espresso.GetDescription()}");

It responds with "Espresso". Now, when using the decorator, the GetDescription method is overridden, in the Mocha class it adds "Mocha" after the beverage's description.

public override string GetDescription()
{
    return beverage.GetDescription() + " Mocha";
}

If I use the override modifier in CondimentDecorator.cs:

public abstract override string GetDescription();

This works as expected. I run:

Beverage espresso = new Espresso();
Console.WriteLine($"{espresso.GetDescription()}"); // Espresso
espresso = new Mocha(espresso);
Console.WriteLine($"{espresso.GetDescription()}"); // Espresso Mocha

However, if I change the modifier to new in CondimentDecorator.cs like this:

public abstract new string GetDescription();

And run the same code, I get the below results:

Beverage espresso = new Espresso();
Console.WriteLine($"{espresso.GetDescription()}"); // Espresso
espresso = new Mocha(espresso);
Console.WriteLine($"{espresso.GetDescription()}"); // Unknown beverage

I'm a little confused why this happens...since GetDescription is being called in Mocha like this...

public override string GetDescription()
{
    return beverage.GetDescription() + " Mocha";
}

...and beverage is a reference back to the original espresso object, why doesn't the code pick up on the description that was set when Espresso was instantiated? The way I understand this, new would hide the original GetDescription method in the base class while override would extend that method. I'm not sure why that would effect which description the program reads -- the "unknown beverage" of Mocha, which gets that value from the Beverage class it derives from, or the "Espresso" of the beverage object I created that had the description set in the constructor.

I'm sure I'm just misunderstanding something basic about inheritance and how the new and override keywords work, if anyone can shed a little light on this I'd appreciate it!

Thanks!

2
  • See: stackoverflow.com/questions/1399127/… Commented Oct 30, 2016 at 6:04
  • 1
    In my experience, a new keyword with a method or property is most often wrong. Hardly anyone understands it, though there might be some rare uses for it. E.g. for our green field projects, I configured the Jenkins build to treat all warnings as errors. One of my colleagues used the same function name in a base class and its derived class which caused a fail. How did he fix that? By taking the suggestion of the compiler. Now the "bug in waiting" was changed to a real bug - the real solution was virtualfor the base class and òverridein the derived class... Commented Oct 31, 2016 at 8:39

2 Answers 2

1

The confusing thing about new is that it creates a second method with the same name as an existing method.

Let's talk about this line of code:

public abstract new string GetDescription();

Thanks to this code, CondimentDecorator now has two GetDescription methods: it has

  • GetDescription, inherited from Beverage, and also
  • GetDescription, newly declared in CondimentDecorator.

Now, whenever you call GetDescription, the compiler has to decide which GetDescription method to call. It does this by looking at the declared type of the variable that you're calling the method on (not the runtime type). If the declared type is Beverage, it calls the method which is inherited from Beverage; if the declared type is CondimentDecorator, it calls the method that's newly declared in CondimentDecorator.

Let's look at your calling code now:

Beverage espresso = new Espresso();
Console.WriteLine($"{espresso.GetDescription()}"); // Espresso
espresso = new Mocha(espresso);
Console.WriteLine($"{espresso.GetDescription()}"); // Unknown beverage

What is happening is that since the declared type of the espresso variable is Beverage, the compiler always interprets this as a call to the GetDescription method which is inherited from Beverage. The fact that the runtime type of espresso is Mocha doesn't matter.

1
  • Thank you, this helped me sort this out in my head -- it's starting to make a bit of sense now :)
    – Jim
    Commented Nov 2, 2016 at 16:46
1

I think this article explains it:

https://msdn.microsoft.com/en-us/library/ms173153.aspx

Basically it depends on whether your beverage is being accessed as a Mocha or and Expresso vs what it actually is.

Assume you have a simple case where

Mocha : Espresso

then

((Espresso)mocha).GetDescription() == "espresso" if you 'new' rather than 'override'

so if you want to do

foreach(Beverage b in List) 
{
    //print description
}

then you should override

Now your particular example is complicated by your decorator. which also inherits from beverage.

you have

Espresso : Beverage

and

Mocha : Decorator : Beverage

so when you use 'new' on Mocha but call

((Beverage)mocha).GetDescription()

you get the Beverage result "unknown beverage"

1
  • Thank you for the useful comment, the casting example you used helped me start thinking about this in the right way...
    – Jim
    Commented Nov 2, 2016 at 16:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.