策略模式(Strategy Pattern):

  我的理解,将代码中每个变化之处抽出,提炼成一个一个的接口或者抽象类,让这些变化实现接口或继承抽象类成为具体的变化类。再利用多态的功能,可将变化之处用接口或抽象类的对象代替,再用其子类为对象赋值,这样就可以将对象随时更换成具体的变化类。

  枯燥的文字描述总是没有实际的例子浅显易懂。

举例:(我是基于notepad++和cmd命令编译运行的JAVA代码)

  现在有个鸭子俱乐部,里面有各式各样的鸭子(只有想不到,没有做不到的鸭子)。

  我们来一步一步实现这个鸭子类:

  1.定义一个抽象鸭子类(Duck):

 public abstract class Duck{//抽象鸭子类
public void fly(){//行为:飞行
System.out.println("I'm flying!");
}
public void quack(){//行为:呱呱叫
System.out.println("Gua Gua!");
}
public void swim(){//行为:游泳
System.out.println("I'm swimming!");
}
}

Duck

  2.实现一个正常的鸭子类(GreenDuck):

 public class GreenDuck extends Duck{//GreenDuck直接继承Duck,什么都不做

     public GreenDuck(){
}
}

GreenDuck

  3.测试类(DuckTest):

 public class DuckTest{//测试类
public static void main(String args[]){
GreenDuck greenDuck = new GreenDuck();//实例化一只GreenDuck
greenDuck.fly();
greenDuck.quack();
greenDuck.swim();
}
}

DuckTest

  编译运行+结果:

  大功告成!我们去庆祝一下。

  正在庆祝,鸭子俱乐部来电话说,我们不仅只要一只GreenDuck,还要RedDuck...不管什么颜色的鸭子都要。你一口应承下来,没问题只是多写几个继承的类而已。

  鸭子俱乐部继续说道,我们还要不会飞,不会叫的橡皮鸭,所有颜色的橡皮鸭来一套。你很心虚的答应了,可能今晚要加班加点了,让各种颜色的橡皮鸭继承Duck但是要覆盖其中的fly和quack行为。

  鸭子俱乐部没完没了的继续说道,我们还要各种颜色的鸭鸣器,它们只会叫不会飞。现在你心里一定恨死各种颜色这个单词了。

  鸭子俱乐部嘴停不下来说各种颜色的...

  .......

  第二天,哭晕在厕所中。

  现在,来看看到底是什么问题导致我们要不停的重复写大量的代码:各种颜色

  没错就是这个单词让我们不停地去写各种各样的鸭子实现类(都继承自Duck抽象类),并且有的鸭子不会飞,有的会飞不会叫...

  现在有没有感觉到继承带来的恐惧感?我们可以让所有的同类鸭子都继承自Duck抽象类,但是每种鸭子都有自己独特的行为,导致我们要不停地去覆盖Duck抽象类中的行为。

  问题找到了。就是继承自抽象类的行为不符合每种鸭子独特的行为导致我们不停地去手动改写或添加行为。我们写这么多的重复代码,没有将代码复用,比如,有的鸭子会飞,有的鸭子会叫,有的鸭子会游泳,有的鸭子不会叫...这么多的行为都写在鸭子实现类中,导致代码冗余,没有将它们复用。

下面让我们的救星:策略模式(Strategy Pattern)登场:

  1.首先,fly()和quack()两个方法是一直在变化的,所以我们将这两个变化之处从Duck抽象类中提炼出来变成FlyBehavior接口和QuackBehavior接口,并在Duck抽象类中定义flyBehavior和quackBehavior两个对象。

 public abstract class Duck{//抽象鸭子类

     /*增加两个接口对象*/
FlyBehavior flyBehavior;//飞行类对象
QuackBehavior quackBehavior;//呱呱叫类对象 public Duck(){
} //去除下面两个方法
/*public void fly(){//行为:飞行
System.out.println("I'm flying!");
}
public void quack(){//行为:呱呱叫
System.out.println("Gua Gua!");
}*/ /*增加下面两个方法,这就是将Duck类的行为委托给两个接口对象实现*/
public void performFly(){//将fly()委托给flyBehavior对象实现
flyBehavior.fly();
}
public void performQuack(){//将quack()委托给quackBehavior对象实现
quackBehavior.quack();
} public void swim(){//行为:游泳
System.out.println("I'm swimming!");
}
}

Duck

 public interface FlyBehavior{//从Duck抽象类中抽出的fly()方法变成了FlyBehavior接口
public void fly();
}

FlyBehavior

 public interface QuackBehavior{//从Duck抽象类中抽出的quack()方法变成了QuackBehavior接口
public void quack();
}

QuackBehavior

  其次,将变化具体类分别继承FlyBehavior和QuackBehavior两个接口:

  两个飞行具体变化类:

 public class FlyWithWings implements FlyBehavior{
public void fly(){
System.out.println("I'm flying!");
}
}

FlyWithWings

 public class FlyNoWay implements FlyBehavior{
public void fly(){
System.out.println("I can't fly!");
}
}

FlyNoWay

  两个呱呱叫具体变化类:

 public class Quack implements QuackBehavior{
public void quack(){
System.out.println("Quack quack!");
}
}

Quack

 public class MuteQuack implements QuackBehavior{
public void quack(){
System.out.println("<< Silence >>");
}
}

MuteQuack

  最后,实现一个具体类和测试类:

 public class GreenDuck extends Duck{//GreenDuck直接继承Duck

     public GreenDuck(){
flyBehavior = new FlyWithWings();
quackBehavior = new Quack();
} /*增加一个展示自己是什么鸭子的方法*/
public void display(){
System.out.println("I'm GreenDuck!");
}
}

GreenDuck

 public class DuckTest{//测试类
public static void main(String args[]){
GreenDuck greenDuck = new GreenDuck();//实例化一只GreenDuck
greenDuck.performFly();
greenDuck.performQuack();
greenDuck.swim();
greenDuck.display();
}
}

DuckTest

编译运行,结果:

上面的结果,我们可以随时随地的实现不同的具体的鸭子类了,只要在具体的鸭子类中为flyBehavior和quackBehavior实现不同的变化类就好。

  2.动态的实现具体变化类的改变:

  在Duck类中添加两个新方法(setFlyBehavior(Flybehavior fb)和 setQuackBehavior(QuackBehavior qb) ):

 public abstract class Duck{//抽象鸭子类

     /*增加两个接口对象*/
FlyBehavior flyBehavior;//飞行类对象
QuackBehavior quackBehavior;//呱呱叫类对象 public Duck(){
} //去除下面两个方法
/*public void fly(){//行为:飞行
System.out.println("I'm flying!");
}
public void quack(){//行为:呱呱叫
System.out.println("Gua Gua!");
}*/ /*增加下面两个方法,这就是将Duck类的行为委托给两个接口对象实现*/
public void performFly(){//将fly()委托给flyBehavior对象实现
flyBehavior.fly();
}
public void performQuack(){//将quack()委托给quackBehavior对象实现
quackBehavior.quack();
} /*添加两个新方法,可以动态的改变具体变化类*/
public void setFlyBehavior(FlyBehavior fb){
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb){
quackBehaior = qb;
} public void swim(){//行为:游泳
System.out.println("I'm swimming!");
}
}

Duck

  改造测试类:

 public class DuckTest{//测试类
public static void main(String args[]){
GreenDuck greenDuck = new GreenDuck();//实例化一只GreenDuck
greenDuck.performFly();//一开始GreenDuck会飞
greenDuck.performQuack();//一开始GreenDuck会叫 /*动态改变greenDuck的行为*/
greenDuck.setFlyBehavior(new FlyNoWay());
greenDuck.setQuackBehavior(new MuteQuack()); greenDuck.performFly();//现在不会飞了
greenDuck.performQuack();//现在不会叫了
}
}

DuckTest

编译运行,结果:

代码下载网址:

https://github.com/lanshanxiao/Head-First-Design-Pattern/tree/master/1.%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F(StrategyPattern)%E8%AE%B2%E8%A7%A3%E4%BB%A3%E7%A0%81/%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0

提炼一下思想:

1.封装

2.“有一个” 比 “是一个” 好(has-a 比 is-a好)

3.多用组合少用继承

4.封装变化

5.针对接口编程,不针对实现编程

1.Strategy Pattern(策略模式)的更多相关文章

  1. Strategy pattern策略模式

    在Java的集合框架中,经常需要通过构造方法传入一个比较器Comparator,或者创建比较器传入Collections的静态方法中作为方法参数,进行比较排序等,使用的是策略模式. 一.策略模式的定义 ...

  2. 设计模式------STRATEGY(策略模式)

    http://blog.csdn.net/wuzhekai1985/article/details/6665197.仅供参考. 策略模式:实现替换功能,如cache替换算法:当发生Cache缺失时,C ...

  3. JAVA设计模式之策略模式 - Strategy

    在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式. 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 ...

  4. PHP设计模式-策略模式 转

    策略模式(Strategy Pattern) 策略模式是对象的行为模式,用意是对一组算法的封装.动态的选择需要的算法并使用. 策略模式指的是程序中涉及决策控制的一种模式.策略模式功能非常强大,因为这个 ...

  5. Provider Pattern提供者模式和策略模式

    http://www.codeproject.com/Articles/18222/Provider-Pattern Introduction Provider pattern is one of t ...

  6. 策略模式-Strategy(Java实现)

    策略模式-Strategy 在策略模式中,一个类(策略使用者)可以更改自己的执行策略. 比如以排序算法为例子, 多种排序算法都归属于排序算法, 但是实现的算法细节不同, 使用者可以很轻松地替换策略, ...

  7. 十、Strategy 策略模式

    需求:使用不同的算法解决相同的问题 设计原理: 代码清单: 接口 Strategy public interface Strategy { public abstract Hand nextHand( ...

  8. 策略模式(Strategy)简介

    一.策略模式(Strategy)简介 策略模式是行为模式. 行为模式:规定了各个对象应该具备的职责以及对象间的通信模式,它很好的规范了对象间调用和数据传递方式 策略模式适合于算法经常变化的情况 算法的 ...

  9. 设计模式复习小结一(Strategy Pattern/Observer Pattern/Decorator Patter/Factory Pattern)

    目录: 前言 1. Stratrgy Pattern 2. Observer Pattern 3. Decorator Pattern 4. Factory Pattern 4.1 FactoryPa ...

  10. Java设计模式—策略模式

    1.策略模式(Strategy Pattern)是一种比较简单的模式,也叫做政策模式(PolicyPattern). 定义如下:     Define a family of algorithms,e ...

随机推荐

  1. AJPFX:外汇的杠杆保证金是什么

    外汇杠杆和保证金两者有着密切的关系.杠杆越大,交易时所用的保证金就越少. 杠杆即为保证金可以缩小的倍数.例如在没有杠杆的情况下,做一手即10万的欧元兑美元货币对合约(现在价格是1.05821),您所需 ...

  2. 日期时间类:Date,Calendar,计算类:Math

    日期时间类 计算机如何表示时间? 时间戳(timestamp):距离特定时间的时间间隔. 计算机时间戳是指距离历元(1970-01-01 00:00:00:000)的时间间隔(ms). 计算机中时间2 ...

  3. 05_python_字典

    一.字典定义 字典是python中唯一的映射类型,以{ }括起来的键值对组成,在dict中key是唯一的.在保存时,根据key来计算一个内存地址,然后把key-value保存至地址中.这种算法是has ...

  4. 前端基础-html 介绍和head标签 ( 1 )

    主要内容 web标准 浏览器介绍 开发工具介绍 HTML介绍 HTML颜色介绍 HTML规范 HTML结构详解 写在前面: 前端               后端 C(client)        S ...

  5. CSS选择器之兄弟选择器(~和+)

    今天在改以以前人家写的网页的样式的时候,碰到这个选择器,‘~’,当时我是懵逼的,傻傻分不清 ‘+’ 跟 ‘~’的区别,虽然我知道他们都是兄弟选择器. 后来网上查了下,也许是我查找的方式不对,没有找到我 ...

  6. Smart/400开发上手3: 练习实践

    练习题 在2006年1月1日之前入职且在职的营销员,给予年资补贴2000元: 符合以上条件的,再按以下标准一次性发放职级补贴: 职级代码 简称 补偿金额 A1 AD 6000 B1 SBM 5000 ...

  7. 生成代码的代码 之 POJO生成器

    我们在写Java代码时候,有时候需要写一些POJO类,也就是只有一些属性和get, set方法的类.例如,在写REST 服务时候,利用Jersery + Jackson,可以把输入的JSON字符串自动 ...

  8. 前端代码质量保障之代码review

    经验丰富的程序员和一般程序员之间的最大区别,不仅体现在解决问题的能力上, 还体现在日常代码的风格上.掌握一门技术可能需要几月,甚至几周就够了. 好的习惯风格养成却需数年. 团队成员之间需要合作,代码需 ...

  9. 解读Secondary NameNode的功能

    1.概述 最近有朋友问我Secondary NameNode的作用,是不是NameNode的备份?是不是为了防止NameNode的单点问题?确实,刚接触Hadoop,从字面上看,很容易会把Second ...

  10. Spring Boot + Spring Cloud 实现权限管理系统 后端篇(五):模块化切分

    切分工程 考虑到后续我们的模块会越来越多,依赖的公共代码和配置需要集中管理,我们在这里先把公共模块和配置从后台管理业务中剥离出来. 新增两个工程,切分后结构如下: kitty-boot:启动器及全局配 ...