So, Im studying Design Patterns, and Im studying the Template Method.
From how I understood it, It is a set of Methods (The skeleton) wrapped in a Method (Operation) on an Abstract Class (If done via heritage), where different Concrete Subclasses write their own implementation of those methods (Not all of them).
But I have a doubt, what happens if some, maybe 2 methods of the skeleton are not used by a certain concretion?, Here I have an example I made, which totally violates the SRP:
using System;
namespace TemplatePattern
{
public abstract class Coffee
{
public void MakeCoffee()
{
HeatWater();
PutCoffee();
if (HaveMilk())
{
PutMilk();
}
if (HaveGratedChocolate())
{
PutGratedChocolate();
}
PutSweetener();
ServeCoffee();
}
internal void HeatWater()
{
Console.WriteLine($"I heated the water");
}
internal void ServeCoffee()
{
Console.WriteLine($"Coffee Served");
}
internal void PutCoffee()
{
Console.WriteLine("I put 2 spoons of Coffee");
}
internal virtual void PutMilk() { }
internal virtual void PutGratedChocolate() { }
internal abstract void PutSweetener();
public virtual bool HaveMilk()
{
return false;
}
public virtual bool HaveGratedChocolate()
{
return false;
}
}
}
Concrete class SimpleCoffeeWithMilk:
using System;
namespace TemplatePattern
{
public class SimpleCoffeWithMilk : Coffee
{
public override bool HaveMilk()
{
return true;
}
internal override void PutSweetener()
{
Console.WriteLine($"I put 1 spoon of Sugar");
}
internal override void PutMilk()
{
Console.WriteLine($"I put 100Cc of Milk");
}
}
}
Another Concrete class:
using System;
namespace TemplatePattern
{
public class CoffeeWithChocolate : Coffee
{
public override bool HaveGratedChocolate()
{
return true;
}
internal override void PutGratedChocolate()
{
Console.WriteLine("Put Chocolate");
}
internal override void PutSweetener()
{
Console.WriteLine($"Put Sugar");
}
}
}
Main Entry Point:
using System;
namespace TemplatePattern
{
class Program
{
static void Main(string[] args)
{
SimpleCoffeWithMilk coffeWithMilk = new SimpleCoffeWithMilk();
CoffeeWithChocolate coffeeWithChocolate = new CoffeeWithChocolate();
coffeWithMilk.MakeCoffee();
Console.WriteLine("\n\n");
coffeeWithChocolate.MakeCoffee();
Console.ReadLine();
}
}
}
The idea is to get rid of those If's Statements, is there any way of doing this with the template method, where some of the methods execute depending of the concrete class?
I was thinking in creating interfaces like ICoffeeWithMilk
with PutMilk()
method on it and implement that interface on my SimpleCoffeeWithMilk
concrete class, but watching the UMLs, the Template Method for what I saw does not rely on Interfaces.
Edit: Now that I think of it, I cant use an interface as, the template method relates to a set of ordered methods in the operation, so these methods are out of the operation.
Edit 2: Ok, I was thinking that PutMilk()
and PutGratedChocolate()
are Hook methods, maybe I can make them abstract methods and in the concrete classes dont put any implementation, not even the not implemented exception class. With this they can exists without any if statements in my Template Method. But I think, Im not sure this violates the Liskov Substitution Principle.
Edit 3: Well... I was thinking, again, and came to the conclusion that, if those methods are virtual and have no implementation on the abstract class, I shouldn't worry about asking, if the concrete class uses that method, then you write the algorithm, if you don't use it, then dont, and it will do nothing, it will go to the next step.