Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my Object still using a method even though I have overriden it?

Tags:

c#

decorator

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:

  1. Beverage Class - Abstract
  2. Espresso Class - Inherits Beverage
  3. BeverageDecorator Class - Abstract
  4. Mocha Class - Inherits Beverage Decotrator

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.

like image 908
Adam Beck Avatar asked Jan 19 '23 03:01

Adam Beck


2 Answers

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

like image 126
Adam Houldsworth Avatar answered Apr 12 '23 22:04

Adam Houldsworth


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
    }
}
like image 38
Jon Skeet Avatar answered Apr 12 '23 22:04

Jon Skeet