《Head First 设计模式》:策略模式
正文
一、定义
策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
要点:
- 策略模式把系统中会变化的部分抽出来封装。
二、实现步骤
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 设计模式》:策略模式的更多相关文章
- 《Android源码设计模式》学习笔记之ImageLoader
微信公众号:CodingAndroid cnblog:http://www.cnblogs.com/angel88/ CSDN:http://blog.csdn.net/xinpengfei521 需 ...
- 《Android源码设计模式》--抽象工厂模式
No1: 4种MediaPlayer Factory分别会生成不同的MediaPlayer基类:StagefrightPlayer.NuPlayerDriver.MidiFile和TestPlayer ...
- 《Android源码设计模式》--Builder模式
No1: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 No2: 在Android源码中,最常用到的Builder模式就是AlertDialog.Builder No3: ...
- 《Android源码设计模式》--策略模式
No1: 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. No2: 使用场景: 1)针对同一类型问题的多种处理方式,仅 ...
- 《Android源码设计模式》--模板方法模式
No1: 模板方法模式包括:抽象类(其中定义了一系列顺序方法).具体实现类A.具体实现类B 如果子类有实现不一样的细节,重写父类的某个方法即可 No2: AsyncTask对象调用execute方法后 ...
- 《Android源码设计模式》--状态模式--责任链模式--解释器模式--命令模式--观察者模式--备忘录模式--迭代器模式
[状态模式] No1: Wifi设置界面是一个叫做WifiSetting的Fragment实现的 No2: 在不同的状态下对于扫描Wifi这个请求的处理是完全不一样的.在初始状态下扫描请求被直接忽略, ...
- 《Android源码设计模式》--享元模式
No1: 享元模式是对象池的一种实现.享元模式用来尽可能减少内存使用量,它适合用于可能存在大量重复对象的场景,来缓存可共享的对象,达到对象共享.避免创建过多对象的效果,这样一来就可以提升性能.避免内存 ...
- 《Android源码设计模式》--工厂方法模式
No1: 对于一个应用程序来说,其真正的入口是在ActivityThread类中,ActivityThread中含有我们熟悉的main方法.ActivityThread是一个final类,不能被继承. ...
- 《Android源码设计模式》--原型模式
No1: 原型模式使用场景: 1)类初始化需要消耗非常多的资源,这个资源包括数据.硬件资源等,通过原型复制避免这些消耗 2)通过new产生一个对象需要非常繁琐的数据准备货访问权限,这是可以使用原型模式 ...
- 《Android源码设计模式》--装饰模式
No1: Activity继承于ContextThemeWrapper,继承于ContextWrapper,继承于Context. No2: Context中方法的所有实现均由ContextImpl类 ...
随机推荐
- vue中给window添加滚动监听无效的解决方案
原文链接: 点我 页面中有这么一个需求,当页面滚动到一定高度之后,页面中的某些元素进行吸顶,固定到顶部位置,或者是滚动到一定程度进行更新数据的操作.我相信不少网友查阅过类似的资料,网友给出的解决方案, ...
- 51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最 ...
- 解决虚拟机中linux系统无法使用本机无线wifi联网的问题
VMware Workstation 在嵌入式开发中经常会遇到,但是显示大多数人使用开发环境是Win10 + 无线网卡,针对这种情况,需要配置虚拟机的上网环境使用的是NAT模式,将配置过程进行描述: ...
- 正方形已知两点对角线求另外两点(POJ2002)
至于为什么,上图.转载于MZW_BG 枚举正方形的一条边,此时有上正方形和下正方形. 最后正方形个数/4,因为每个正方形被枚举了4条边 #include <bits/stdc++.h> u ...
- 【x64软路由】OpenWrt(LEDE) 20200329编译 反追踪 抗污染 加速 PSW 无缝集成 UPnP NAS
固件说明 基于Lede OpenWrt R2020.3.19版本(源码更新截止20200329)Lienol Feed及若干自行维护的软件包 结合家庭x86软路由场景需要定制 按照家庭应用场景对固件及 ...
- 【Spark】DataFrame关于数据常用操作
文章目录 DSL语法 概述 实例操作 SQL语法 概述 实例操作 DSL语法 概述 1.查看全表数据 -- DataFrame.show 2.查看部分字段数据(有4种方法) (1) DataFram ...
- 【Hadoop离线基础总结】Hive的基本操作
Hive的基本操作 创建数据库与创建数据库表 创建数据库的相关操作 创建数据库:CREATE TABLE IF NOT EXISTS myhive hive创建表成功后的存放位置由hive-site. ...
- python小游戏-pygame模块
一.tkinter模块的GUI 基本上使用tkinter来开发GUI应用需要以下5个步骤: 导入tkinter模块中我们需要的东西. 创建一个顶层窗口对象并用它来承载整个GUI应用. 在顶层窗口对象上 ...
- DP动态规划之01背包问题
目录 问题描述 问题分析 问题求解 Java代码实现 优化方向一:时间方面:因为是j是整数是跳跃式的,可以选择性的填表. 思考二:处理j(背包容量),w(重量)不为整数的时候,因为j不为整数了,它就没 ...
- 关于oracle怎么看清楚字段的一些实践
在oracle存储过程或者平时编码中会有很多时候对不上字段,这时候在字段逗号后面可以主动加上--数字. 还有的是应该注意尽量让每个字段都占有一行的空间.下面部分截图说明