最近两周工作比较忙,一直疏忽了写博客这件事。但是再忙也得坚持下去,虽然很难,但是自己定下的小目标含着泪也要把它做下去啊~~好了,废话不多说直接进入正题吧。
设计模式相信大家应该都有接触过,并且在不经意间也使用过一些设计模式,使用设计模式最重要的一点是让我们的代码看起来更清晰可读,并且更具可扩展性,还可以达到代码最大程度复用的目标。所以今天我就来介绍一下最近在项目中用到的两个设计模式,这两个设计模同样也是使用的比较多的两个模式:模板方法模式以及策略模式。
模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。模板方法模式需要开发抽象类和具体子类。抽象类给出一个算法的轮廓和骨架,具体类则负责给出这个算法的各个各个特定逻辑步骤。代表这些具体逻辑步骤的方法称做基本方法(primitivemethod);而将这些基本方法汇总起来的方法叫做模板方法(templatemethod),这个设计模式的名字就是从此而来。
模板方法所代表的行为称为顶级行为,其逻辑称为顶级逻辑。模板方法模式的静态结构图如下所示:
这里涉及到两个角色:
抽象模板(AbstractTemplate)角色有如下责任:
■定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。
■定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。
具体模板(ConcreteTemplate)角色又如下责任:
■实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。
■每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。
有句名言说的好:Talkischeap.Showmethecode…拿出代码才有说服力嘛!那么我们就以炒菜这件事为例来实现一下模板方法模式吧。首先我们来梳理一下,如果要做一个菜需要做些什么事项,以及这些事项的顺序。俗话说,巧妇难为无米之炊。。。那最先肯定需要原材料,所以就需要去买菜;买到菜之后就是考验动手能力的时候了,需要洗菜,切菜以及做菜了。通过我个人总结,这个世界上的所有菜都有个基本操作顺序:买菜-->洗菜-->准备菜-->做菜-->出锅,所有菜的做法都是大概就是这个抽象的流程。因此,我们可以构建一个抽象类来定义这些流程,代码如下:
1、炒青菜
1packagecom.guigui.common.patterns.template;23/**4*炒青菜类5*/6publicclassCookGreensextendsAbstractCook{7@Override8protectedvoidsetDishName(){9this.dishName="青菜";10}1112@Override13protectedvoidprepareDisher(){14System.out.println("开始摘"+dishName+"...");15System.out.println("开始切"+dishName+"...");16System.out.println("开始对"+dishName+"进行过水...");17System.out.println("开始准备蒜瓣,并将其切碎...");18}1920@Override21protectedvoidfryDishes(){22System.out.println("倒油并烧开...");23System.out.println("倒入蒜瓣爆香...");24System.out.println("倒入"+dishName+"进行翻炒3分钟...");25}26}实现了准备菜和做菜这两个抽象方法,内容对应青菜的做法。
2、蒸鸡蛋
1packagecom.guigui.common.patterns.template;23/**4*蒸鸡蛋类5*/6publicclassCookEggsextendsAbstractCook{7@Override8protectedvoidsetDishName(){9this.dishName="鸡蛋";10}1112@Override13protectedvoidwashDishes(){14//鸡蛋不需要清洗,这里用一个空方法重写覆盖15}1617@Override18protectedvoidprepareDisher(){19System.out.println("打破"+dishName+"壳,并放入碗中...");20System.out.println("捣碎"+dishName+"蛋黄和蛋清,搅拌至均匀...");21System.out.println("倒入一定量的清水以及油和盐...");22}2324@Override25protectedvoidfryDishes(){26System.out.println("在蒸锅中放入一定量水...");27System.out.println("放入隔层...");28System.out.println("放入准备好的"+dishName+",盖上锅盖蒸10到15分钟...");29}30}实现蒸鸡蛋的准备方法与做法,另外鸡蛋不需要洗,所以把洗菜这个方法实现成了一个空的方法,表示这个菜是不需要清洗的。
3、烧排骨
1packagecom.guigui.common.patterns.template;23/**4*烧排骨类5*/6publicclassCookRibsextendsAbstractCook{7@Override8protectedvoidsetDishName(){9this.dishName="排骨";10}1112@Override13protectedvoidprepareDisher(){14System.out.println("剁碎洗干净后的"+dishName+"...");15System.out.println("准备一定量的葱姜蒜,并切碎...");16System.out.println("将准备好的"+dishName+"在锅中进行焯水处理后盛出...");17}1819@Override20protectedvoidfryDishes(){21System.out.println("在锅中倒入油并烧开...");22System.out.println("倒入准备好的葱姜蒜爆香...");23System.out.println("放入焯水后的排骨进行翻炒5到10分钟...");24System.out.println("倒入一定量料酒,及其他调料,继续翻炒几分钟...");25}26}实现了排骨的具体做法。
以上便是模板方法模式的具体实现;下面继续介绍另外一个常用的设计模式:策略模式,策略模式经常和模板方法模式结合起来使用,模板方法规定主流程,具体的实现分别对应不同的策略。
策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。下图为策略模式具体结构:
这个模式涉及到三个角色:
●环境(Context)角色:持有一个Strategy的引用。
●抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
还是以上述做菜的例子为例说明,做菜的抽象流程类便是抽象策略角色,每一种菜的实现都可以当做是一个具体策略角色,然后我们还需要加上一个环境角色,来完善这个策略模式,下面代码示例即为环境角色类:
1packagecom.guigui.common.patterns.strategy;23importcom.guigui.common.patterns.template.AbstractCook;45publicclassContext{6//持有具体策略对象7privateAbstractCookcookDish;8//构造方法,传入具体策略对象9publicContext(AbstractCookcookDish){10this.cookDish=cookDish;11}12//执行策略方法13publicvoidstrategyProcess(){14cookDish.fryProcess();15}16}这样便完成了策略模式的基本结构。下面写一个示例来演示一下模板方法模式和策略模式结合起来使用过程,以下为测试类代码:
测试结果:
好了,今天要介绍的内容大概就是这么多,有什么不对的地方欢迎大家指正,非常感谢~~~