正文

一、定义

策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

要点:

  • 策略模式把系统中会变化的部分抽出来封装。

二、实现步骤

1、创建策略接口

/**
* 策略接口
*/
public interface Strategy { /**
* 执行策略行为
*/
public void perform();
}

2、创建策略接口的实现类

(1)策略实现类 A

/**
* 策略实现类A
*/
public class StrategyImplA implements Strategy { /**
* A策略行为
*/
@Override
public void perform() {
System.out.println("perform A...");
}
}

(2)策略实现类 B

/**
* 策略实现类B
*/
public class StrategyImplB implements Strategy { /**
* B策略行为
*/
@Override
public void perform() {
System.out.println("perform B...");
}
}

3、在使用策略的类中,声明并使用接口类型的策略变量

/**
* 策略使用者
*/
public class StrategyUser { /**
* 声明接口类型的策略变量
*/
private Strategy strategy; /**
* 通过构造实例化策略
*/
public StrategyUser(Strategy strategy) {
this.strategy = strategy;
} /**
* 执行策略使用者的行为
*/
public void doBehavior() {
// do something... // 使用策略
strategy.perform(); // do something...
}
}

4、通过实例化不同的策略实现类,来改变使用者的行为

public class Test {

    public static void main(String[] args) {
// 使用策略A
StrategyUser userA = new StrategyUser(new StrategyImplA());
userA.doBehavior();
// 使用策略B
StrategyUser userB = new StrategyUser(new StrategyImplB());
userB.doBehavior();
}
}

三、举个栗子

1、背景

Joe 上班的公司做了一套相当成功的模拟鸭子游戏:SimUDuck。游戏中会出现各种鸭子,鸭子的种类及属性如下:

  • 种类:绿头鸭、红头鸭、橡皮鸭、诱饵鸭。
  • 属性:外观、游泳行为、飞行行为、呱呱叫行为(叫声)。

不同种类的鸭子所对应的属性如下:

  • 绿头鸭:绿头鸭的外观、会游泳、会飞行、呱呱叫。
  • 红头鸭:红头鸭的外观、会游泳、会飞行、呱呱叫。
  • 橡皮鸭:橡皮鸭的外观、会游泳(漂浮)、不会飞行、吱吱叫。
  • 诱饵鸭:诱饵鸭的外观、会游泳(漂浮)、不会飞行、不会叫。

2、要点

  • 由于不同种类的鸭子可能具有不同的飞行行为、呱呱叫行为,因此,可以使用策略模式把这两种行为抽出来。

3、实现

(1)创建行为接口

/**
* 飞行行为接口
*/
public interface FlyBehavior { public void fly();
}
/**
* 呱呱叫行为接口
*/
public interface QuackBehavior { public void quark();
}

(2)实现行为接口

/**
* 用翅膀飞行
*/
public class FlyWithWings implements FlyBehavior { @Override
public void fly() {
System.out.println("I'm flying!");
}
} /**
* 不会飞行
*/
public class FlyNoWay implements FlyBehavior { @Override
public void fly() {
System.out.println("I can't flying!");
}
}
/**
* 呱呱叫
*/
public class Quack implements QuackBehavior { @Override
public void quark() {
System.out.println("Quack");
}
} /**
* 吱吱叫
*/
public class Squeak implements QuackBehavior { @Override
public void quark() {
System.out.println("Squeak");
}
} /**
* 不会叫
*/
public class MuteQuack implements QuackBehavior { @Override
public void quark() {
System.out.println("<<Silence>>");
}
}

(3)创建鸭子抽象类,并使用行为接口

/**
* 鸭子抽象类
*/
public abstract class Duck { FlyBehavior flyBehavior;
QuackBehavior quackBehavior; public Duck() {
} /**
* 外观
*/
public abstract void display(); /**
* 游泳行为
*/
public void swim() {
System.out.println("All ducks float, even decoys!");
} /**
* 飞行行为
*/
public void performFly() {
flyBehavior.fly();
} /**
* 呱呱叫行为
*/
public void performQuark() {
quackBehavior.quark();
}
}

(4)创建鸭子子类,并指定具体的行为实现

/**
* 绿头鸭
*/
public class MallardDuck extends Duck { public MallardDuck() {
// 指定具体的飞行行为
flyBehavior = new FlyWithWings();
// 指定具体的呱呱叫行为
quackBehavior = new Quack();
} @Override
public void display() {
System.out.println("I'm a real Mallard duck");
}
} /**
* 红头鸭
*/
public class RedHeadDuck extends Duck { public RedHeadDuck() {
// 指定具体的飞行行为
flyBehavior = new FlyWithWings();
// 指定具体的呱呱叫行为
quackBehavior = new Quack();
} @Override
public void display() {
System.out.println("I'm a red head duck");
}
} /**
* 橡皮鸭
*/
public class RubberDuck extends Duck { public RubberDuck() {
// 指定具体的飞行行为
flyBehavior = new FlyNoWay();
// 指定具体的呱呱叫行为
quackBehavior = new Squeak();
} @Override
public void display() {
System.out.println("I'm a rubber duck");
}
} /**
* 诱饵鸭
*/
public class DecoyDuck extends Duck { public DecoyDuck() {
// 指定具体的飞行行为
flyBehavior = new FlyNoWay();
// 指定具体的呱呱叫行为
quackBehavior = new MuteQuack();
} @Override
public void display() {
System.out.println("I'm a decoy duck");
}
}

(5)测试

public class Test {

    public static void main(String[] args) {
// 绿头鸭
MallardDuck mallardDuck = new MallardDuck();
mallardDuck.performFly();
mallardDuck.performQuark();
// 红头鸭
RedHeadDuck redHeadDuck = new RedHeadDuck();
redHeadDuck.performFly();
redHeadDuck.performQuark();
// 橡皮鸭
RubberDuck rubberDuck = new RubberDuck();
rubberDuck.performFly();
rubberDuck.performQuark();
// 诱饵鸭
DecoyDuck decoyDuck = new DecoyDuck();
decoyDuck.performFly();
decoyDuck.performQuark();
}
}

《Head First 设计模式》:策略模式的更多相关文章

  1. 《Android源码设计模式》学习笔记之ImageLoader

    微信公众号:CodingAndroid cnblog:http://www.cnblogs.com/angel88/ CSDN:http://blog.csdn.net/xinpengfei521 需 ...

  2. 《Android源码设计模式》--抽象工厂模式

    No1: 4种MediaPlayer Factory分别会生成不同的MediaPlayer基类:StagefrightPlayer.NuPlayerDriver.MidiFile和TestPlayer ...

  3. 《Android源码设计模式》--Builder模式

    No1: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 No2: 在Android源码中,最常用到的Builder模式就是AlertDialog.Builder No3: ...

  4. 《Android源码设计模式》--策略模式

    No1: 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. No2: 使用场景: 1)针对同一类型问题的多种处理方式,仅 ...

  5. 《Android源码设计模式》--模板方法模式

    No1: 模板方法模式包括:抽象类(其中定义了一系列顺序方法).具体实现类A.具体实现类B 如果子类有实现不一样的细节,重写父类的某个方法即可 No2: AsyncTask对象调用execute方法后 ...

  6. 《Android源码设计模式》--状态模式--责任链模式--解释器模式--命令模式--观察者模式--备忘录模式--迭代器模式

    [状态模式] No1: Wifi设置界面是一个叫做WifiSetting的Fragment实现的 No2: 在不同的状态下对于扫描Wifi这个请求的处理是完全不一样的.在初始状态下扫描请求被直接忽略, ...

  7. 《Android源码设计模式》--享元模式

    No1: 享元模式是对象池的一种实现.享元模式用来尽可能减少内存使用量,它适合用于可能存在大量重复对象的场景,来缓存可共享的对象,达到对象共享.避免创建过多对象的效果,这样一来就可以提升性能.避免内存 ...

  8. 《Android源码设计模式》--工厂方法模式

    No1: 对于一个应用程序来说,其真正的入口是在ActivityThread类中,ActivityThread中含有我们熟悉的main方法.ActivityThread是一个final类,不能被继承. ...

  9. 《Android源码设计模式》--原型模式

    No1: 原型模式使用场景: 1)类初始化需要消耗非常多的资源,这个资源包括数据.硬件资源等,通过原型复制避免这些消耗 2)通过new产生一个对象需要非常繁琐的数据准备货访问权限,这是可以使用原型模式 ...

  10. 《Android源码设计模式》--装饰模式

    No1: Activity继承于ContextThemeWrapper,继承于ContextWrapper,继承于Context. No2: Context中方法的所有实现均由ContextImpl类 ...

随机推荐

  1. 程序猿使用Python的tkinter库进行GUI编程肯定要会的事件处理

    事件类型用户通过鼠标.键盘.游戏控制设备在与图形界面交互时,就会触发事件.tkinter事件通常采用了将事件名称放置于尖括号内的字符串表示,尖括号中的内容我们称之为事件类型.事件类型有其通用的定义方式 ...

  2. Java笔记(day20-22)

    IO流: 输入流.输出流 字节流.字符流:为了处理文字数据方便而出现的对象. (其实这些对象的内部使用的还是字节流(因为文字最终也是字节数据,只不过,通过字节流读取了相对应的字节数,没有对这些字节直接 ...

  3. Java——Java泛型

    该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 一.泛型概述 1.定 ...

  4. [LiDAR数据模拟]系列(1) HELIOS模拟平台介绍

    关键词:LiDAR 激光雷达 点云模拟 作者:李二 日期:06/05/2020 - 07/05/2020 写在前面:我前段时间的一个工作(地基激光雷达TLS的新型布站策略)需要用到模拟的TLS点云数据 ...

  5. 支付宝小程序serverless---获取用户信息(头像)并保存到云数据库

    支付宝小程序serverless---获取用户信息(头像)并保存到云数据库 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! 我又 ...

  6. CSS的基本语法及页面引用

    CSS的基本语法及页面引用 CSS基本语法 CSS的定义方法是: 选择器 { 属性:值; 属性:值; 属性:值;} 选择器是将样式和页面元素关联起来的名称,属性是希望设置的样式属性每个属性有一个或多个 ...

  7. 你离高薪 offer 只差一个Redis入门,我是认真的

    说起来,可能有些小伙伴会不相信,我是第一次用 Redis,真的.因为公司小,业务量小,Redis 根本派不上用场.不过,最近打算把系统升级一下,顺带把当下时髦的技术入个门,"与时俱进&quo ...

  8. GNU ARM 汇编基础

    ARM GNU汇编基础 0 前言 全文补充提醒: 笔者在阅读ARM官方文档及查阅实际的u-boot源码中的汇编代码后,发现了一些不同于ARM官方文档中的汇编语法,查阅相关资料后,才发现主要由于汇编器的 ...

  9. netty零基础入门

    直接上代码,从最基本的接收消息规则开始 package cn.qdl; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelH ...

  10. SpringBoot 整合Mail发送功能问题与解决

    SpringBootLean 是对springboot学习与研究项目,是根据实际项目的形式对进行配置与处理,欢迎star与fork. [oschina 地址] http://git.oschina.n ...