一直没有养成写博客的习惯,很早就打算通过设计模式来开始博客之旅,后面因为上半年找工作对并发知识缺乏。就学了一阵子以并发相关内容开始写博客了,现在才写了几篇,之后会继续完善。现在在阅读《Head First设计模式》,刚好博客记录下学习过程。都知道设计模式在OO编程中很重要,理解和在实际中运用完全不是同一回事,但是在运用之前我们起码的先学会不是吗?
下面我们将通过一个烹饪鸡的例子来更好的理解(至于为什么是烹饪鸡,仅仅只是喜欢吃鸡肉);
首先我们定义一个Person接口类
这个person有很多技能(吃饭睡觉打豆豆),我们不关注,本场景下我们用到的只有一个cookieChicken(烹饪鸡肉)
//人物类
public interface Person {
//烹饪鸡肉
void cookingChicken();
}
接下来本篇博客主角陈师傅登场
//陈师傅
public class MasterChen implements Person {
@Override
public void cookingChicken() {
System.out.println("辣子鸡");
}
}
陈师傅(也喜欢吃鸡肉),尤其是辣子鸡,所以他烹饪鸡的做法,第一种就学的辣子鸡
好,接下来我们把鸡肉交给陈师傅
public static void main(String[] args) {
Person masterChen = new MasterChen();
masterChen.cookingChicken();
}
陈师傅也不负众望,做出了美味的辣子鸡
辣子鸡
天天吃一种菜总是会腻的,尽管喜欢吃,陈师傅依稀记得在重庆旅游的时候,吃过一次正宗的重庆鸡公煲,味道很是美味,话不多话,就是干。陈师傅开始学重庆鸡公煲的做法,不久后出师。
现在我们构造的陈师傅应该怎么样适应变化呢?恩 一开始肯定都是这么想的,我们改造下
//人物类
public interface Person {
//烹饪鸡肉
void cookingChicken(String type);
}
人物类中烹饪鸡肉我们增加一个type区分不同的做法
//陈师傅
public class MasterChen implements Person {
@Override
public void cookingChicken(String type) {
if(type.equals("辣子鸡")){
System.out.println("辣子鸡");
}else if(type.equals("重庆鸡公煲")){
System.out.println("重庆鸡公煲");
}
}
}
现在的陈师傅可以通过type,来用不同的烹饪方式烹饪鸡肉
public static void main(String[] args) {
Person masterChen = new MasterChen();
masterChen.cookingChicken("辣子鸡");
masterChen.cookingChicken("重庆鸡公煲");
}
辣子鸡
重庆鸡公煲
恩,这样我们的目的的确达到了,偶然的一次机会,陈师傅到广州沟通学习,并学会了白切鸡的做法。
为了适应变化,我们又要修改我们构造的陈师傅。不过在修改之前,我们思考一个问题,每次陈师傅新学一种烹饪鸡肉的做法,我们就要修改我们构造的陈师傅,这是不是不合适呢?在OO编程中,我们一直主张对扩展开发,对修改关闭。我们此刻的做法就违背这个原则。在实际生产中我们应该也是尽量做到新增功能不影响原有的功能。
此刻,策略模式隆重登场,在这个场景中,不断变化的是烹饪鸡的做法,我们可以把其看做策略模型中的算法抽离出来。以后增加算法都不影响原有的功能。
这里我们先把类之间的关系图放出来(烹饪鸡肉行为和人物分离然后组合进来)
人物类改造
public abstract class Person {
//烹饪鸡肉的行为
CookChicken cookChicken = null;
//烹饪鸡肉
abstract void cookingChicken();
public void setCookChicken(CookChicken oneCookChicken){
cookChicken =oneCookChicken;
}
}
这里我们将人物类由接口改成了抽象类,将烹饪鸡肉这一做法抽离成行为的方式(面对接口编程不一定是指完全面对Interface编程,关键在于多态。利用多态,程序可以针对超类型编程,某些场景下抽象类比接口更合适)
烹饪鸡肉行为类
public interface CookChicken {
void cooking();
}
同时,针对辣子鸡,和白切鸡我们定义了两个实现类
辣子鸡:
public class SpicyChicken implements CookChicken {
@Override
public void cooking() {
System.out.println("辣子鸡");
}
}
白切鸡:
public class WhiteCutChicken implements CookChicken {
@Override
public void cooking() {
System.out.println("白切鸡");
}
}
重庆鸡公煲:
public class ChongqingChicken implements CookChicken {
@Override
public void cooking() {
System.out.println("重庆鸡公煲");
}
}
最后就是经过改造的陈师傅,此刻的陈师傅能够灵活运用多种烹饪鸡肉的做法
public class MasterChen extends Person {
public MasterChen() {
cookChicken = new SpicyChicken();
}
@Override
public void cookingChicken() {
//默认用陈师傅最熟悉的辣子鸡来实例化
cookChicken.cooking();
}
}
接下来到了关键的做菜过程了
public class Test {
public static void main(String[] args) {
Person masterChen = new MasterChen();
masterChen.cookingChicken();
masterChen.setCookChicken(new ChongqingChicken());
masterChen.cookingChicken();
masterChen.setCookChicken(new WhiteCutChicken());
masterChen.cookingChicken();
}
}
辣子鸡
重庆鸡公煲
白切鸡
经过我们的改造,我们能在运行时通过setCookChicken在陈师傅工作期间,动态用不同的烹饪手法,做出不同的鸡肉(辣子鸡、重庆鸡公煲、白切鸡)。今后即时陈师傅各种深造,学习更多地烹饪鸡肉的做法。我们也只需要实现更多地烹饪行为实现类,无需对陈师傅进行各种改造。
这就是策略模式,通过将某些相同系列算法抽离程序,在组合进去,使得系统更具有弹性。
最后我们在回顾一次策略模式的定义,是不是理解更深刻了呢
参考资料:《Head First 设计模式》