模板方法和删除If语句

时间:2018-06-27 08:20:59

标签: c# design-patterns template-method-pattern

因此,我正在研究设计模式,而我正在研究模板方法。

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

但是我有一个疑问,如果某种结石未使用某些骨架方法(也许有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;
        }
    }
}

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

另一个具体课程:

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("\n\n");

            coffeeWithChocolate.MakeCoffee();

            Console.ReadLine();

        }
    }
}

想法是摆脱那些If语句,是否可以通过模板方法来做到这一点,其中某些方法根据具体的类执行?

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

编辑:现在,我想起来了,我不能使用接口,因为模板方法与操作中的一组有序方法有关,所以这些方法不在操作之列。 / p>

编辑2:好吧,我在想PutMilk()PutGratedChocolate()是Hook方法,也许我可以将它们设为抽象方法,而在具体的类中不要放置任何实现,甚至没有实现的异常类也没有。有了它们,它们可以存在,而我的模板方法中没有任何if语句。但是我认为,我不确定这是否违反了《里斯科夫换人原则》。

编辑3:嗯……我再次思考,得出的结论是,如果这些方法是虚拟的并且在抽象类上没有实现,那么我不必担心询问,如果具体类使用该方法,则编写算法,如果不使用,然后不编写算法,它将什么都不做,它将继续进行下一步。

2 个答案:

答案 0 :(得分:1)

只需删除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
    }
}

关于您对此解决方案的关注,我认为它不违反Liskov。 LSP声明,子类型必须可以替代其基类的任何其他继承者,这些情况是这样的。您可以调用PutMilk,它们将放置适合其接口专业化的所有牛奶。这些变化都不会影响调用方法。明确地说,您可以构想一个可以做到这一点的示例,但是在这种情况下,您不会在那里遇到问题。

答案 1 :(得分:0)

您可以将选择语句(在这种情况下为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");
        }
    }
}

我坚信后者是您想要的。