原标题:设计模式之模板方法模式(封装算法)
下面,我们的学习将从咖啡和茶的制作上开始进行。 泡茶的步骤: 下面,用代码来实现上面的步骤: 茶的实现: 从上面的代码可以发现,有两个步骤我们是重复了的,我们可以把重复的部分抽取出来,放入到一个基类中。 下面看一幅图,来看看我们现在都做了些什么: 模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现 模板方法模式:在一个方法定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤 钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类决定。 让我们看看它在实际代码里面的应用 测试: 当算法的某个实现可选的时候,可以使用钩子。当算法的某个实现是必须的时候,使用抽象方法 钩子可以让子类有能力为其基类做一些决定。 好莱坞原则:别调用我们,我们会调用你。 我们在之前设计模板方法的时候,其实就用到了好莱坞原则: 在这里我们看到好莱坞原则感觉和依赖倒置原则很像,都是用于解耦。 使鸭子类继承至IComparable接口,之后使用sort方法进行排序 排序 在上面的例子中,我们可以看到子类提供的实现排序方法的算法。设计模式之模板方法模式(封装算法)
第一次设计
泡咖啡的步骤:
咖啡的实现:public class Coffee
{
void prepareRecipe()
{
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}
public void boilWater()
{
Console.WriteLine("Boiling water");
}
public void brewCoffeeGrinds()
{
Console.WriteLine("Dripping Coffee through filter");
}
public void pourInCup()
{
Console.WriteLine("Pouring into cup");
}
public void addSugarAndMilk()
{
Console.WriteLine("Adding Sugar and milk");
}
}
public class Tea
{
void prepareRecipe()
{
boilWater();
brewTeaBag();
addLemon();
pourInCup();
}
public void boilWater()
{
Console.WriteLine("Boiling water");
}
public void brewTeaBag()
{
Console.WriteLine("Steeping the tea");
}
public void pourInCup()
{
Console.WriteLine("pouring into cup");
}
public void addLemon()
{
Console.WriteLine("Adding Lemon");
}
}
改进
把boilWater()、pourInCup()提取出来放入基类,把prepareRecipe()定义成抽象方法。但这样定义,对于prepareRecipe()仍然需要实现两次,我们将boilWater()、pourInCup()泛化,使用brew()和addCondiments()来替代,并且在基类中,将其定义成抽象方法。这样prepareRecipe()不在抽象,而是在基类中实现。
基类: public abstract class CaffeineBeverage
{
public void prepareRecipe()
{
boilWater();
brew();
addCondiments();
pourInCup();
}
public void boilWater()
{
Console.WriteLine("Boiling water");
}
public void pourInCup()
{
Console.WriteLine("pouring into cup");
}
public abstract void brew();
public abstract void addCondiments();
}
什么是模板方法
在上面的代码中,我们模板方法就是prepareRecipe(),原因:
定义模板方法模式
这个抽象类包含了模板方法。
primitiveOperation1()、primitiveOperation2()模板方法所用到的操作的抽象版本,模板方法本身和这两个操作的具体实现之间被解耦。
一个模板方法中可能许多具体类,这个具体类实现了抽象类的操作。钩子(对模板方法进行挂钩)
下面来看看代码怎么写: public abstract class CaffeineBeverageWithHook
{
void prepareRecipe()
{
boilWater();
brew();
poueInCup();
if (customerWantsCondiments())
{
addCondiments();
}
}
public abstract void brew();
public abstract void addCondiments();
void boilWater()
{
Console.WriteLine("Boiling water");
}
void poueInCup()
{
Console.WriteLine("Pouring into cup");
}
bool customerWantsCondiments()//这就是一个钩子,子类可以覆盖(这个方法通常是空的实现)
{
return true;
}
}
使用钩子
子类继承: public class CoffeeWithHook : CaffeineBeverageWithHook
{
public override void addCondiments()
{
Console.WriteLine("Adding Sugar through filter");
}
public override void brew()
{
Console.WriteLine("Dripping Coffee through filter");
}
public override bool customerWantsCondiments()
{
Console.WriteLine("Adding Sugar through filter?Y/N");
string s = Console.ReadLine();
if (s=="y")
{
return true;
}
return false;
}
}
static void Main(string[] args)
{
CoffeeWithHook coffeewithhool=new CoffeeWithHook();
coffeewithhool.prepareRecipe();
Console.ReadKey();
}
关于钩子
什么时候使用钩子
钩子的目的
好莱坞原则
好莱坞原则防止依赖腐败:当高层组件依赖底层组件,而底层组件又依赖高层组件,而高层组件又依赖边测组件,边侧组件又依赖高层组件,这样依赖腐败就发生了。
在好莱坞原则下,我们允许底层组件将自己挂钩到系统上,但高层组件会决定什么时候调用这些底层组件。好莱坞原则应用
在上面图中,CaffeineBeverage就是我们的高层组件,它能够控制冲泡方法的算法,只有在需要子类实现某个方法是才调用,饮料的客户代码只依赖CaffeineBeverage的抽象,而不依赖具体的类。好莱坞原则和依赖倒置原则
依赖倒置原则让我们尽量避免使用具体类,而多使用抽象,它更加注重与在设计中避免依赖。
好莱坞原则则是一种用在创建框架或组件上的一种技巧,好让底层组件能够被挂钩计算,而又不会让高层组件依赖底层组件,它是创建一个有弹性的设计,允许底层结构能够互相操作,而又防止太过于依赖。使用模板方法来排序
public class Duck:IComparable
{
private string name;
private int weight;
public Duck(string name, int weight)
{
this.name = name;
this.weight = weight;
}
public string toString()
{
return name + "weighs" + weight;
}
public int CompareTo(object obj)//需要提供的实现
{
Duck otherDuck = (Duck) obj;
if (this.weight<otherDuck.weight)
{
return -1;
}
else if (this.weight==otherDuck.weight)
{
return 0;
}
else
{
return 1;
}
}
}
static void Main(string[] args)
{
List<Duck> ducks=new List<Duck>{new Duck("11",11),new Duck("2",2),new Duck("13",13),new Duck("7",7)};
DisPlay(ducks);
ducks.Sort();
DisPlay(ducks);
Console.ReadKey();
}
当前文章:http://neomi.cn/play_80930.html
发布时间:2019-02-17 11:22:50
发发棋牌中心 合声棋牌游戏吧 火萤棋牌app器炸金花 蓝洞棋牌谁有下载地址 南通金游棋牌游戏中心 扑克迷龙哥 扑克王直播 手机版集结号捕鱼游戏 天地棋牌电脑板 天健棋牌大厅下载
21049 61847 73710 84492 62864 9105212220 77033 70338
责任编辑:董伯秉平