A dislike of Inheritance - Reused
In the original A dislike of inheritance post I used an example that I've actually diverged from.
Most of you will think this is overkill... but ... Things change for one reason in one place. Just hear my out... read me out?
In the original post these were the classes I ended up with
public sealed class MushroomTopping : Topping
{
public MushroomTopping() : base("Mushroom", new RegularToppingCost()) { }
}
public sealed class RegularToppingCost : ToppingCost
{
//contents not provided
}
I've diverged from this. It didn't sit quite right with me. It felt like I wasn't taking the same idea of creating smaller and more specific classes futher. It solved a problem I had, but... it exposed a different smell.
I'm here to show you that solution!
The issue comes up with the "Pizza Shop" when I change the price of mushrooms in a later phase. Not the price of regular toppings; just mushroom.
What do we do?
If mushroom has a unique cost, we have to create that.
public sealed class MushroomTopping : Topping
{
public MushroomTopping() : base("Mushroom", new MushroomToppingCost()) { }
}
We don't have a "Regular Topping Cost" anymore. It's become an invalid concept in the code. We can't assume a valid concept today is always a valid concept; sometimes it needs to go away as our understanding and complexity grows.
If we left it like this; we'd have 2 ways to do topping costs. An "everyone" topping and "specific toppings" that deviate from the norm. I hate having two ways to do things. I think it confuses the code because it doesn't know what it wants to be.
What I have been doing with my playing in the "Pizza Shop" is to create topping specific costs, as shown above.
This looks wrong to me. Why is there a hard coded value chilling... If it was
public sealed class MushroomTopping : Topping
{
public MushroomTopping() : base("Mushroom", 0.11) { }
}
with multiple hard coded values, I'd be "ok" with it. Not great, I think the loss of meta-data is a killer.
WHat about "Mushroom"
- What is it? A string; no. That's data. It's a description. Maybe a description component... Which is an idea I just had... and may solve a smell I've been sensing... I'll try that later...
Back to this issue; "Mushroom" isn't being adequately represented. It's concept is missing from the code. Our base "Topping" takes a string... it takes in raw data... BOOOOOO!
public sealed class MushroomTopping : Topping
{
public MushroomTopping() : base("Mushroom", new MushroomToppingCost()) { }
}
public sealed class MushroomToppingCost : ToppingCost
{
public MushroomToppingCost() : base(.11) { }
}
public sealed class MushroomToppingDescription : ToppingDescription
{
public MushroomToppingDescription() : base("Mushroom") { }
}
Now I have these three classes. They all have a single responsibility. They all do one thing; they know A PIECE of information about a mushroom topping.
It's a lot more small classes... but it's not called MicroObjects for no reason. :)
These are easy to crank out; easy to test; easy to visually validate correctness... they don't DO anything... all testing is around the base classes. One of the few instances I use inheritance to great effect.
summary
That's it. Saw a concept I evolved further than I'd posted about it; and wanted to share.