模板方法和删除 if 语句



所以,我正在研究设计模式,我正在研究模板方法。

根据我的理解,它是一组方法(骨架(,包装在抽象类上的方法(操作((如果通过遗产完成(,其中不同的具体子类编写自己的这些方法的实现(不是全部(。

但我有一个疑问,如果某种凝固不使用某些(也许是 2 种骨架(方法会发生什么?,这里我举了一个例子,这完全违反了 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;
}
}
}

混凝土类简单咖啡加牛奶:

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");
}
}
}

另一个具体类:

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");
}
}
}

主要入口点:

using System;
namespace TemplatePattern
{
class Program
{
static void Main(string[] args)
{
SimpleCoffeWithMilk coffeWithMilk = new SimpleCoffeWithMilk();
CoffeeWithChocolate coffeeWithChocolate = new CoffeeWithChocolate();
coffeWithMilk.MakeCoffee();
Console.WriteLine("nn");
coffeeWithChocolate.MakeCoffee();
Console.ReadLine();
}
}
}

这个想法是摆脱那些 If 的语句,有没有办法使用模板方法做到这一点,其中某些方法根据具体类执行?

我正在考虑创建像ICoffeeWithMilk这样的接口PutMilk()并在我SimpleCoffeeWithMilk的具体类上实现该接口,但是观察 UML,我所看到的模板方法不依赖于接口。

编辑:现在我想到了,我不能使用接口,因为模板方法与操作中的一组有序方法相关,因此这些方法不在操作中。

编辑2:好的,我在想PutMilk()PutGratedChocolate()是Hook方法,也许我可以使它们抽象方法,并且在具体类中不放置任何实现,甚至没有实现异常类。有了这个,它们可以在我的模板方法中没有任何 if 语句存在。但我认为,我不确定这是否违反了利斯科夫替代原则。

编辑3:嗯...我又想了想,得出的结论是,如果这些方法是虚拟的,在抽象类上没有实现,我不应该担心问,如果具体类使用该方法,那么你编写算法,如果你不使用它,那么不要,它什么也不做,它会进入下一步。

只需删除if语句,让凝结物通过实现它们来做出决定,如下所示:

public abstract class Coffee
{
public void MakeCoffee()
{
PutMilk();
}
protected abstract void PutMilk();
}
public class SimpleCoffeWithMilk : Coffee
{    
public override void PutMilk()
{
Console.WriteLine($"I put 100Cc of Milk");
}
}
public class SimpleCoffeNoMilk : Coffee
{    
public override void PutMilk()
{
//no op
}
}

至于你对这个解决方案的担忧,我认为它没有违反利斯科夫。 LSP 声明子类型必须可替换为其基类的任何其他继承者,这些情况就是这种情况。 您可以为其中任何一个调用PutMilk,他们将投放适合其界面专业化的所有牛奶。 这些变化都不会影响调用方法。 需要明确的是,您可以设计一个可以做到这一点的示例,但在这种情况下,您不会在那里遇到问题。

您可以将选择语句(在本例中为 if 语句(转移到模板中,但如果您需要检查某些条件,则无法摆脱它们。天气你这样做

public abstract class Coffee
{
public abstract bool HaveMilk();
public void MakeCoffee()
{
if (HaveMilk())
{
PutMilk();
}
}
}
public class SimpleCoffeWithMilk : Coffee
{
public bool HaveMilk()
{
return true;
}
public override void PutMilk()
{
Console.WriteLine($"I put 100Cc of Milk");
}
}

或者像这样

public abstract class Coffee
{
public void MakeCoffee()
{
PutMilk();
}
}
public class SimpleCoffeWithMilk : Coffee
{
public bool HaveMilk()
{
return true;
}
public override void PutMilk()
{
if (HaveMilk())
{
Console.WriteLine($"I put 100Cc of Milk");
}
}
}

我坚信后者是你要找的。

最新更新