Baseclass Asking Subclasses for Items

There are many scenarios where a baseclass (often abstract) needs to defer to its subclasses the creation (or retrieval) of items it needs. For example, let’s pretend we have a Pizza class, which defers to its subclasses what ingredients it should have. I’ve seen developers implementing such scenario in ways that look like this:

public abstract class Pizza
{
    List<string> Ingredients { get; set; }

    protected abstract void AddIngredients(List<string> ingredients);

    public void Make()
    {
        AddIngredients(Ingredients);
    }
}

public class MeatLovers : Pizza
{
    protected override void AddIngredients(List<string> ingredients)
    {
        ingredients.Add("Pepperoni");
        ingredients.Add("Sausage");
        ingredients.Add("Canadian Bacon");
    }
}

That kind of implementation has the baseclass call a method overridden in the subclass so it can populate the given list. I don’t like it implemented this way because it gives developers the idea that the list can be manipulated. For example, the developer might decide that before adding items to the list, he or she could/should empty the list first (ingredients.Clear()). Well, what if I want all of my pizzas to have cheese (I’m a cheesy guy!)?

I rather ask the subclass for the items, and then have the baseclass deal with adding them to a list, collection, array, or however it sees fit. Something like this:

public abstract class Pizza
{
    List Ingredients { get; set; }

    protected abstract IEnumerable<string> GetIngredients();

    public void Make()
    {
        Ingredients = GetIngredients().ToList();
    }
}

public class MeatLovers : Pizza
{
    protected override IEnumerable<string> GetIngredients()
    {
        yield return "Pepperoni";
        yield return "Sausage";
        yield return "Canadian Bacon";
    }
}

In simple scenarios, the subclass can simply use yield return for each item. For other cases, it can internally use lists, collections, arrays, or anything else that can ultimately produce an IEnumerable<string>.

With that being said, if the requirements calls for allowing the baseclass to manipulate that list, then I’d go with something similar to the first implementation. However, in most cases, that’s NOT what the requirements ask for, and I’ve had to troubleshoot several bugs where subclasses manipulated lists when they were not really meant to.

Advertisements

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: