设计模式Java语言实现之策略模式(生动有趣版)

策略模式:

前言:

作者:韩数

Github:https://github.com/hanshuaikang

时间:2019-01-26

JDK版本:1.8

定义:

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

适用范围:

1.在一个系统中,有很多相似的类,而区分这些类的仅仅是不同的行为。那么策略模式可以像电脑主机一样模块化的让一个对象在不同的行为中选择一种一种行为。

2、一个系统需要动态地在几种算法中选择一种。

3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

优缺点:

优点:

代码耦合度比较底,相对来说比较灵活一些

可以避免使用if else多重判断语句

比较有弹性,可扩展性比较好

缺点

策略类会比较多,之后的代码实战中会发现这个问题

所有策略类都需要对外暴露

前提引入:

韩数独创之对话流:

老板: 阿呆,你去给我编写一个鸭子类(严重吐槽,请大家不要想歪,本书依靠head frist系列书籍,为了避免读者读书的时候代码和书籍有不同的地方影响理解,故没有修正)

阿呆: 内心戏(不就写个实体类吗。写个Duck类,然后把鸭子外貌,飞,叫这样的特征定义了,方法实现了就OK了,Nice,完美),老板没问题,保证完成任务!

a week has later.... 阿呆信心满满的把写好的Duck类交给了老板。

老板: 不错,写的不错,哎呀,可是,我突然又想要一只橡皮鸭,这只鸭子,不会飞,吱吱叫,我小时候最喜欢的玩具,这样吧,你去写写这个啥橡皮鸭吧。

阿呆:(内心戏: 这橡皮鸭,这,跟我上次写的那个鸭子不是一个品种啊,怎么还吱吱叫,鸭子不都嘎嘎嘎叫吗,算了,不就是再写一个类继承Duck类吗,把fly,quack,display这三个方法覆盖重写了就好了,Nice,完美,我简直是一个天才!)老板没问题,保证完成任务!

a week has later.... 阿呆信心满满的把写好的RubberDuck类交给了老板。

老板: 不错,真好,对了,阿呆呀,我那个侄女,她喜欢那个绿毛鸭,会飞,咕咕叫,头上长绿毛的那种,你看能写么?

阿呆:(内心戏:MMP,略) 老板没问题,保证完成任务!

a week has later...

老板: 那个黑天鸭...

阿呆:(内心戏:emmmmmp) 老板没问题,保证完成任务!

老板: 那个七小天鸭...

阿呆:(内心戏:emmmmmp) 老板没问题,保证完成任务!

老板: 那个派大鸭...

阿呆:(内心戏:emmmmmp) 老板没问题,保证完成任务!

a year has later...

阿呆:卒

这么玩儿下去肯定不行,只通过继承,必然可以完成老板的要求,万一有一万只不同品种的鸭子,不敢往下想了,而且Duck是所有类的父类,这要是Duck改一点点,想到后面还有几万个Duck的孩子要改,不禁倒吸一口凉气,这是,阿呆的弟弟二呆出场了,说:

这世间鸭子千千万,不过数种,记得我之前给你讲那个电脑主机的故事么,把所有零件设计成可拆卸更换的模块

只留下那个大家通用的模块不要动,在鸭子身上就是游泳,哪种鸭子不会游泳?你说,其他的,飞呀,叫什么的,我们单独分离出来,最后老板要啥鸭子,我们给他组装一下不就得了。

此时,设计模式中一句宝典浮出水面,那就是:分离变和不变的部分。

大家听了不禁啧啧称赞,纷纷叹道妙呀,妙呀,真是妙啊!

代码实战:

焕然一新后的鸭子类:

public abstract class Duck {
​
 /*
 * 面向超类编程,主类Duck只保留所有鸭子通用不变的特征比如游泳
 * 变化的部分单独封装,提高代码的弹性,避免因为单一的向下继承
 * 造成的代码的灵活性降低,避免过于耦合情况的发生。
 */

 FlyBehavior flyBehavior;
 QuackBehavior quackBehavior;

 public Duck() {
 }

 //定义set方法,可以动态的设定鸭子飞行的行为
 public void setFlyBehavior (FlyBehavior fb) {
 flyBehavior = fb;
 }

 //定义set方法,可以动态的设定鸭子飞行的行为
 public void setQuackBehavior(QuackBehavior qb) {
 quackBehavior = qb;
 }

 //鸭子的外表,这里定义为抽象方法,父类只做声明,不负责实现
 abstract void display();

 //鸭子的行为,Duck不适合实现,交给相应的模块实现。
 public void performFly() {
 flyBehavior.fly();
 }

 public void performQuack() {
 quackBehavior.quack();
 }

 //所有鸭子都会游泳
 public void swim() {
 System.out.println("All ducks float, even decoys!");
 }
}

可能会有人不太懂,FlyBehavior flyBehavior; QuackBehavior quackBehavior;是什么意思,你想啊,虽然显卡,CPU,音响,内存条都模块化了,但是也总的留个插头方便接入不是。

定义飞行行为的接口,为啥是接口呢?不是类,面向接口(超类)编程,可以更好的利用面向对象中的多态,第二个也可以提高程序相互调用中的安全性。提高程序的灵活性,可扩展性。

public interface FlyBehavior {
 public void fly();
}

同理叫声接口:

public interface QuackBehavior {
 public void quack();
}

比如嘎嘎叫的鸭子,我们就定义一个Quack类实现QuackBehavior的接口,并编写quack方法的实现为嘎嘎叫,吱吱叫的鸭子,我们就定义一个Squeak类实现QuackBehavior的接口,并编写quack方法的实现为吱吱叫,等等,咕咕叫,喔喔叫,哇我叫,等等等等等,你开心就好。飞的行为同理。

/***
 * 
 * 定义鸭子叫声是嘎嘎嘎的行为
 * 
 */
​
​
public class Quack implements QuackBehavior {
 public void quack() {
 System.out.println("嘎嘎嘎");
 }
}
​
​
​
/***
 * 
 * @author hansu
 * 定义鸭子吱吱叫的行为
 * 
 */
​
​
public class Squeak implements QuackBehavior {
 public void quack() {
 System.out.println("吱吱吱");
 }
}
​
/***
 * 
 * 定义鸭子不会飞的行为
 * 
 *
 */
​
public class FlyNoWay implements FlyBehavior {
 public void fly() {
 System.out.println("哎,难过,我不会飞");
 }
}
​
​
​
/***
 * 
 * 定义鸭子是会飞的行为
 *
 */
​
public class FlyWithWings implements FlyBehavior {
 public void fly() {
 System.out.println("我会飞!哈哈哈");
 }
}
​

好了,现在模块是写好了,可是,我们怎么样编写鸭子的子类把这些模块装上去呢?二呆缓缓说,急啥,且听我娓娓道来。

哟,要是想把这些模块来组装

那你就要深入进去它的心房

把模块放入构造器中

变成一把直接就上膛的手枪

yo,freestyle

比如橡皮鸭的特征是吱吱叫,不会飞,身子是橡皮做的,于是就把FlyNoWay,Squeak模块组装一下,然后只需实现一下父类Duck的display方法就会得到一只崭新的完全满足甲方要求的橡皮鸭了!

如下:

/***
 * 
 * demo1:橡皮鸭,特征,不会飞,吱吱叫
 *
 */
​
public class RubberDuck extends Duck {

 public RubberDuck() {
 /*
 * 注:因为RubberDuck继承Duck类,所有Duck类中定义的
 * flyBehavior和quackBehavior可以直接赋值
 */
 //定义橡皮鸭不会飞的行为
 flyBehavior = new FlyNoWay();
 //定义橡皮鸭吱吱叫的行为
 quackBehavior = new Squeak();
 }

 public void display() {
 System.out.println("我是一个橡皮鸭,我的身体是橡皮做哒");
 }
}

编写测试代码Text:

public class Text {

 public static void main(String[] args) {
 Text t = new Text();
 t.rubberDuckDemoText();

 System.out.println("\n现在有请活的鸭子闪亮登场!\n");

 t.liveDuckDemoText();
 }

 public void rubberDuckDemoText() {

 RubberDuck rubberDuck = new RubberDuck();
 rubberDuck.display();
 rubberDuck.performFly();
 rubberDuck.performQuack();
​

 }

 public void liveDuckDemoText() {

 LiveDuck liveDuck = new LiveDuck();
 liveDuck.display();
 liveDuck.performFly();
 liveDuck.performQuack();

 }

​
}

Out:

我是一个橡皮鸭,我的身体是橡皮做哒 I can't fly 吱吱吱

现在有请活的鸭子闪亮登场!

我是一只活鸭子 我会飞!哈哈哈 嘎嘎嘎

最后,二呆和老板幸福的生活在了一起。

实战总结:

在这里大家就会发现了,虽然这样的确比继承单一Duck类重写方法方便高效了很多,但是如果鸭子特征超级多的话,也需要编写超级多的行为类,同时,每个行为类都必须是可实例化的,这针对某些情况来说并不太适合,但是,设计模式有二十七种呢,更不要说其他设计模式了,更是多到数不胜数,所以在合适的情况下选择合适的设计模式可以显著提高我们代码的效率和质量,这点是毋庸置疑的。

写在最后:

欢迎大家给小星星,您的星星是我写下去的不竭动力!

源码部分请移步本人Github下载:

Github地址:

Github:https://github.com/hanshuaikang/design-pattern-java

参考资料:

菜鸟教程:http://www.runoob.com/design-pattern/strategy-pattern.html

Head frist of 设计模式

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容

  • 本文参照《Head First 设计模式》,转载请注明出处对于整个系列,我们按照这本书的设计逻辑,使用情景分析的方...
    诡异的叶子阅读 605评论 0 5
  • Git命令大全 git config 配置 Git 的相关参数。 Git 一共有3个配置文件: 1. 仓库级的配置...
    笑叶林阅读 142,691评论 11 141
  • 2016年,经历的事不多,后半年只有一件——考研。 期间摇摆不定,但从没质疑过自己的方向。 也不知道该说些什么,这...
    格格曙阅读 199评论 0 0
  • #幸福是需要修出来的~每天进步1%~幸福实修13班~22唐洁# 20180102(36/60) 【幸福三朵玫瑰】 ...
    你谢谢阅读 148评论 0 2
  • 昨天一位两个孩子的爸爸很困惑的问我两个问题,1.他说他的两个孩子很贪玩,静不下心来学习;2、他在家里的时候和不...
    47c5277e96f6阅读 153评论 0 0