Jak wygląda ta definicja przenosząc ją do rzeczywistości?
A więc wyobraźmy sobie bardzo prostą czynność: robienie herbaty i robienie kawy.
Robienie herbaty:
- Zagotuj wodę
- Wsyp trochę ziaren herbaty do szklanki
- Wlej gorącą wodę do szklanki
- Dodaj cukru i cytryny
- Zagotuj wodę
- Wsyp trochę kawy do szklanki
- Wlej gorącą wodę do szklanki
- Dodaj cukru i mleka
Spójrzmy na UML:
Tak w skrócie wygląda wzorzec Template Method. Tworzymy jedną abstrakcyjną klasę która będzie nadzorowała cały przebieg algorytmu. W środku klasy definiujemy metody (poszczególne kroki algorytmu) które będą dwojakiego rodzaju: abstrakcyjne oraz zaimplementowane z góry. Te kroki które dla wszystkich kroków są takie same zostaną zaimplementowane w klasie abstrakcyjnej. Kroki które różnią się dla każdego z algorytmów zostaną zaimplementowane w konkretnych podklasach. Przejdźmy więc do rzeczy:
public abstract class MakeDrink
{
public virtual void BoildWater()
{
Console.WriteLine("The water is boiling...");
}
public abstract void AddIngredien();
public virtual void SpilCup()
{
Console.WriteLine("I spil the cup");
}
public abstract void AddCondiment();
public void Run()
{
BoildWater();
AddIngredien();
SpilCup();
AddCondiment();
}
}
public class Tea : MakeDrink
{
public override void AddIngredien()
{
Console.WriteLine("I'm adding some tea leaf");
}
public override void AddCondiment()
{
Console.WriteLine("I'm adding sugar and limone");
}
}
public class Coffee : MakeDrink
{
public override void AddIngredien()
{
Console.WriteLine("I'm adding some cofee beans");
}
public override void AddCondiment()
{
Console.WriteLine("I'm adding sugar milk");
}
}
class Program
{
static void Main(string[] args)
{
MakeDrink md = new Tea();
md.Run();
Console.WriteLine();
md = new Coffee();
md.Run();
}
}
Jak widać, zostało zaimplementowane to wszystko, co wcześniej zostało napisane.
Z wzorcem Template Method związane są jeszcze tzw. hooked methods - czyli metody które można ale nie trzeba nadpisywać. Jeśli nie nadpiszemy ich w klasie potomnej - klasa abstrakcyjna zapewni im domyślne zachowanie. Dla przykładu pozwolimy wybrać użytkownikowi czy chce do kawy jakieś dodatki:
public abstract class MakeDrink
{
public virtual void BoildWater()
{
Console.WriteLine("The water is boiling...");
}
public abstract void AddIngredien();
public virtual void SpilCup()
{
Console.WriteLine("I spil the cup");
}
public abstract void AddCondiment();
public void Run()
{
BoildWater();
AddIngredien();
SpilCup();
if (CutomerWantCondiment())
{
AddCondiment();
}
}
public virtual bool CutomerWantCondiment()
{
return true;
}
}
public class Tea : MakeDrink
{
public override void AddIngredien()
{
Console.WriteLine("I'm adding some tea leaf");
}
public override void AddCondiment()
{
Console.WriteLine("I'm adding sugar and limone");
}
}
public class Coffee : MakeDrink
{
public override void AddIngredien()
{
Console.WriteLine("I'm adding some cofee beans");
}
public override void AddCondiment()
{
Console.WriteLine("I'm adding sugar milk");
}
public override bool CutomerWantCondiment()
{
String answer = CustomerAnswer();
if (answer == "y")
{
return true;
}
return false;
}
private string CustomerAnswer()
{
Console.WriteLine("Do you want some sugar and lemon for your tea? y/n");
return Console.ReadLine();
}
}
class Program
{
static void Main(string[] args)
{
MakeDrink md = new Tea();
md.Run();
Console.WriteLine();
Coffee c = new Coffee();
c.Run();
}
}
Tak więc dzięki Template Method uzyskaliśmy:
- Łatwe zarządzanie algorytmem z jednego miejsca (klasy)
- Zmniejszenie ilości powtarzanego kodu
- Algorytm zapisaliśmy w jednym miejscu = łatwiejsza modyfikacja w przyszłości
Brak komentarzy:
Prześlij komentarz