C#设计模式之9:模板方法

模板方法

模板方法是一个方法,定义了算法的步骤,并允许子类为一个或多个步骤提供实现。

本例中用冲泡咖啡和茶的例子来说明:

上图说明了冲泡咖啡和茶的步骤,可以看出冲泡咖啡和茶的步骤差不多,很相似,先来看看没有应用模板方法的代码:

Tea的代码类似,就不放了。他们的一个不好的地方在于算法散落在了各个类中,还有一点是重复的代码。

public abstract class CaffeineBeverage//设计一个抽象类,将算法进行封装
    {
        public void BoilWater()
        {
            Console.WriteLine("boil water");
        }

        public void PourInCup()
        {
            Console.WriteLine("pour in cup");
        }

        public void PrepareRecipe()//封装算法,这个就是模板方法。
        {
            BoilWater();
            Brew();
            PourInCup();
            AddCondiment();
        }
        public abstract void Brew();//具体的实现要到子类中实现
        public abstract void AddCondiment();//具体的实现要到子类中实现
    }
    public class TeaLogic: CaffeineBeverage
    {
        public override void Brew()
        {
            Console.WriteLine("brew tea");
        }

        public override void AddCondiment()
        {
            Console.WriteLine("add some lemon");
        }
    }
    public class CoffeLogin:CaffeineBeverage
    {
        public override void Brew()
        {
            Console.WriteLine("brew coffe...");
        }

        public override void AddCondiment()
        {
            Console.WriteLine("add some milk and sugar...");
        }
    }

模板方法定义了一个算法步骤,并允许子类其中一个或多个实现提供步骤。

模板方法的定义:在一个方法中定义算法的骨架,而将一些步骤延迟到子类中。模板方法可以在子类不改变算法结构的情况下,重新定义算法中的某些步骤。

同时,AbstractClass内部定义一个钩子方法——一个虚方法,可以在子类中决定是否重写,达到挂钩的目的。钩子的存在,可以让子类有能力对算法的不同点进行挂钩,要不要挂钩,由子类自行决定。

//在模板方法中应用钩子
    public abstract class AnotherKindOfCoffeineBeverage
    {
        public void BoilWater()
        {
            Console.WriteLine("boil water");
        }
        public void PourInCup()
        {
            Console.WriteLine("pour in cup..");
        }
        public virtual bool CustomerWantCondiment()//虚方法。。表示一个钩子
        {
            return true;
        }
        public abstract void Brew();
        public abstract void AddCondiment();
        public void PrepareRecipe()
        {
            BoilWater();
            Brew();
            if (CustomerWantCondiment())
            {
                AddCondiment();
            }
            PourInCup();
        }
    }
    //应用钩子方法的一个场景
    public class AnotherKindOfTea : AnotherKindOfCoffeineBeverage
    {
        public override bool CustomerWantCondiment()
        {
            return GetCustomerInput().Equals("y");
        }
        public override void Brew()
        {
            Console.WriteLine("dropping coffe through filter..");
        }
        public override void AddCondiment()
        {
            Console.WriteLine("add some condiment..");
        }
        private string GetCustomerInput()
        {
            Console.WriteLine("would you like some lemon with your tea?(y/n)");
            var input = Console.ReadLine();
            return input?.ToLower();
        }
    }

 

关于钩子,由这么一个原则:当你必须提供模板方法中的某个步骤时,就在基类中做成抽象方法,如果这个步骤是可选的,就做成虚方法,钩子。

钩子可以让子类实现算法中的可选部分,或者在钩子对于子类的实现不那么重要的时候,子类可以对此钩子置之不理。钩子的另一个用法,是让子类能够有机会对模板方法中某些即将发生的步骤做出反应。钩子也可以让子类有能力为其抽象类做一些决定。

最重要的一点:抽象类中的某些方法是可选的,对于这些可选的方法,就做成钩子,而不是做成抽象方法,这样就可以让子类的负荷减轻。

新的设计原则:好莱坞设计原则——不要调用(打电话给)我们,我会调用(打电话给)你。

 

 

好莱坞原则和模板方法

他们两个的联系还算是比较明显:当我们设计模板方法时,我们告诉子类,“不要调用我们,我们会调用你”。

好莱坞原则和依赖倒置原则之间的关系:

 

posted @ 2018-04-09 11:33  wall-ee  阅读(288)  评论(0编辑  收藏  举报