23种设计模式 第三部分 关系模式(2)模板方法模式
来源:互联网 发布:网络信息安全认证 编辑:程序博客网 时间:2024/06/05 18:59
理解
模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。
泡茶和泡咖啡,步骤很相似:
两种饮品其分别的做法如下代码:
public class Coffee { public void PrepareRecipe() { //烧水 BoilWater(); //冲咖啡 BrewCoffeeGrinds(); //倒入茶杯中 PourInCup(); //加入糖和咖啡 AddSugarAndMilk(); } public void BoilWater() { Console.WriteLine("烧水"); } public void BrewCoffeeGrinds() { Console.WriteLine("冲咖啡"); } public void PourInCup() { Console.WriteLine("倒入杯子中"); } public void AddSugarAndMilk() { Console.WriteLine("加糖和牛奶"); } }public class Tea { public void PrepareRecipe() { //烧水 BoilWater(); //泡茶 SteepTeaBag(); //倒入茶杯中 PourInCup(); //加入柠檬 AddLemon(); } public void BoilWater() { Console.WriteLine("烧水"); } public void SteepTeaBag() { Console.WriteLine("泡茶"); } public void PourInCup() { Console.WriteLine("倒入杯子中"); } public void AddLemon() { Console.WriteLine("加柠檬"); } }烧水和带入杯子的方法显然是重复的,这样就不符合代码复用。
对比两种做法,都是需要四个步骤,把相同的使用一个基类,不同的部分分别由自己的子类去实现。
冲咖啡和泡茶以及加入咖啡和牛奶都是属于差不多动作相同的。所以可以继续抽象,抽象为“泡”和“加调料”。抽象后的方法大致如此:
得出的也就是我们的模板方法。下面来看看模板方法模式的类图:
实现
public abstract class CoffeeinBeverage1{ public void BoilWater() { Console.WriteLine("烧水"); } public void PrepareRecipe() { BoilWater(); Brew(); PourInCup(); AddCondiments(); } public void PourInCup() { Console.WriteLine("倒入杯子中"); } public abstract void Brew(); public abstract void AddCondiments();}咖啡:
public class Coffee1 : CoffeeinBeverage1{ public override void Brew() { Console.WriteLine("冲咖啡"); } public override void AddCondiments() { Console.WriteLine("加糖和牛奶"); }茶:
public class Tea1 : CoffeeinBeverage1{ public override void Brew() { Console.WriteLine("泡茶"); } public override void AddCondiments() { Console.WriteLine("加柠檬"); }}
分析
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法似的自雷可以在不改变算法结构的情况下,重新定义算法中的某些步骤。这个模式用来创建一个算法的模板。什么是模板?如你所见,模板就是一个方法。更具体的说,这个方法将算法定义成一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现。这可以确保算法的结构保持不变,同时由子类提供部分实现。
模板方法挂钩(使用钩子)
在上面的茶水和咖啡中,现在是看起来能喝了,但是有个问题就是有些人喝咖啡喜欢不加任何调味料的。那么我们硬是给客人加,肯定是会生气的。为了满足这个要求,设计模式提供的有这个解决方案——使用钩子。具体什么是钩子,我们小的时间的课本上有个猴子捞月亮的图片:
钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子可以让子类幼儿管理对算法的不同点进行挂钩(子类决定是否覆盖抽象类中的方法)。
public void PrepareRecipe() { BoilWater(); Brew(); PourInCup(); //有个判断方法来添加调料 if (WantCondiments()) { AddCondiments(); } } /// <summary> /// 加入一个方法,用来判断是否需要加调料 /// </summary> /// <returns></returns> public virtual bool WantCondiments() { return true; }
在子类中,可以通过不同的方式类覆盖WantCondiment()方法。用来表示是否要加调料的标准,在此方法中注意必须加入virtual关键字,以便子类中使用override重写。下面看看咖啡中的方法:
public override bool WantCondiments() { return false; }
咖啡:
class Program { static void Main(string[] args) { CoffeeinBeverage1 coffeninBeverage = new Coffee1(); coffeninBeverage.PrepareRecipe(); Console.ReadKey(); } }
输出:
已经去掉了调料。
模板方法模式还涉及到一个好莱坞原则:
别调用(打电话给)我们,我们会调用(打电话给)你。
在模板方法模式中扮演好莱坞的角色是抽象类,子类是演员的角色。
我们允许低层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件。换句话说,高层组件对待低层组件的方式是“别调用我们,我们会调用你。”我们要做的事,避免让高层和低层组件之间有明显的环状依赖。
总结
模板方法 - -> 封装可互换的行为,然后使用委托来决定要采用哪一个行为。
策略 -- >子类决定如何实现算法中的步骤。
工厂方法 -- > 由子类决定实例化哪个具体类。
- 23种设计模式 第三部分 关系模式(2)模板方法模式
- 23种设计模式 第三部分 关系模式(1)策略模式
- 23种设计模式 第三部分 关系模式(3)观察者模式
- 23种设计模式 第三部分 关系模式(4)迭代子模式
- 23种设计模式 第三部分 关系模式(5)责任链模式
- 23种设计模式 第三部分 关系模式(6)命令模式
- 23种设计模式-模板方法模式
- 23种设计模式(6):模板方法模式
- 《设计模式解析》第三部分 设计模式
- 《设计模式解析》第三部分 设计模式
- Android Ap 开发 设计模式第三篇:模板方法模式
- Android App 开发 设计模式第三篇:模板方法模式
- Android 设计模式第三篇:模板方法模式
- 23种设计模式~模板方法的设计模式
- PHP设计模式-模板模式(模板方法模式)
- PHP设计模式-模板模式(模板方法模式)
- java(2) 设计模式-模板方法设计模式
- 23种设计模式4--行为型模式(策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式)
- 聊天界面之ListView
- 《Google C++ 编程风格指南》对于头文件的包含顺序
- linux常用环境变量和c/c++头文件/库路径环境变量
- C++指针的定义
- jQuery_解析xml文件
- 23种设计模式 第三部分 关系模式(2)模板方法模式
- 坚持#第23天~嘻嘻家玩了一天
- 网络异常,dns异常,qq能上但是网页打不开
- 修饰符(static、final、abstract)第一篇
- OpenGL + VS2015 + Windows10配置
- 折腾Ubuntu16.04
- C++指针 续
- QGroundControl —— MAVLink 命令
- Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace