设计模式——策略模式
本片博文学习尚硅谷韩老师《设计模式》课程所做,在此非常感谢!
概述
策略模式的基本介绍
- 策略模式(Strategy Pattern)中,定义算法族(策略组),分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户;
- 这算法体现了几个设计原则,第一、把变化的代码从不变的代码中分离出来;第二、针对接口编程而不是具体类(定义了策略接口);第三、多用组合/聚合,少用继承(客户通过组合方式使用策略);
注意事项
- 策略模式的关键是:分析项目中变化部分与不变部分;
- 策略模式的核心思想是:多用组合/聚合 少用继承;用行为类组合,而不是行为的继承。更有弹性;
- 体现了“对修改关闭,对扩展开放”原则,客户端增加行为不用修改原有代码,只要添加一种策略(或者行为)即可,避免了使用多重转移语句(if…else if…else);
- 提供了可以替换继承关系的办法: 策略模式将算法封装在独立的 Strategy 类中使得你可以独立于其 Context 改变它,使它易于切换、易于理解、易于扩展;
- 需要注意的是:每添加一个策略就要增加一个类,当策略过多是会导致类数目庞大;
UML
问题引入
编写鸭子项目,具体要求如下:
- 有各种鸭子(比如 野鸭、北京鸭、水鸭等, 鸭子有各种行为,比如 叫、飞行等)
- 能够显示鸭子的信息
- 能够如上面所描述的一样,只通过
一行代码(策略或者行为)
就可以修改某个鸭子的属性;
我们通过策略模式来实现这个需求
编码实现
UML
首先构建出这个需求的UML图,如下所示:
编码
我们创建行为接口
,分别是飞的行为
、游泳的行为
、叫的行为
,如下所示:
package edu.hebeu.strategy.strategys.flybehavior;
public interface FlyBehavior {
/**
* 飞的方法
*/
void fly();
}
package edu.hebeu.strategy.strategys.swimbehavior;
public interface SwimBehavior {
/**
* 游泳的方法
*/
void swim();
}
package edu.hebeu.strategy.strategys.quackbehavior;
public interface QuackBehavior {
/**
* 叫的方法
*/
void quack();
}
然后在这个三个行为接口的基础上各自实现几个对应的子类,如飞的行为接口
的实现类:擅长飞
、不擅长飞
、不会飞
;游泳的行为接口
的实现类有:擅长游泳
、不擅长游泳
、不会游泳
;叫的行为接口
的实现类:GaGaQuackBehavior
、GeGeQuackBehavior
、NotQuackBehavior
,具体编码如下:
飞的行为接口
的实现类
package edu.hebeu.strategy.strategys.flybehavior;
public class GoodFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("非常擅长飞");
}
}
package edu.hebeu.strategy.strategys.flybehavior;
public class BadFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("飞的技术很一般");
}
}
package edu.hebeu.strategy.strategys.flybehavior;
public class NotFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("不会飞");
}
}
游泳的行为接口
的实现类
package edu.hebeu.strategy.strategys.swimbehavior;
public class GoodSwimBehavior implements SwimBehavior{
@Override
public void swim() {
System.out.println("非常擅长游泳");
}
}
package edu.hebeu.strategy.strategys.swimbehavior;
public class BadSwimBehavior implements SwimBehavior{
@Override
public void swim() {
System.out.println("游泳技术一般");
}
}
package edu.hebeu.strategy.strategys.swimbehavior;
public class NotSwimBehavior implements SwimBehavior{
@Override
public void swim() {
System.out.println("不会游泳");
}
}
叫的行为接口
的实现类
package edu.hebeu.strategy.strategys.quackbehavior;
public class GaGaQuackBehavior implements QuackBehavior{
@Override
public void quack() {
System.out.println("嘎嘎嘎~~~");
}
}
package edu.hebeu.strategy.strategys.quackbehavior;
public class GeGeQuackBehavior implements QuackBehavior {
@Override
public void quack() {
System.out.println("咯咯咯~~~");
}
}
package edu.hebeu.strategy.strategys.quackbehavior;
public class NotQuackBehavior implements QuackBehavior {
@Override
public void quack() {
System.out.println("不能叫");
}
}
此时所有的行为(策略)
就准备完毕了,我们此时创建一个抽象的使用类Duck
,然后让这个类将所有的行为接口
聚合,如下:
package edu.hebeu.strategy.user;
import edu.hebeu.strategy.strategys.flybehavior.FlyBehavior;
import edu.hebeu.strategy.strategys.quackbehavior.QuackBehavior;
import edu.hebeu.strategy.strategys.swimbehavior.SwimBehavior;
/**
* 所有的鸭子的抽象基类
* @author 13651
*
*/
public abstract class Duck {
// 聚合所有的策略
protected FlyBehavior fly;
protected QuackBehavior quack;
protected SwimBehavior swim;
/**
* 展示鸭子的所有信息
*/
public abstract void display();
/**
* 飞的方法
*/
public final void fly() {
if(fly != null) { // 如果fly不为null,就调用fly的fly()方法
fly.fly();
return;
}
System.out.println("鸭子会飞"); // 程序执行到此,说明fly为null
}
/**
* 叫的方法
*/
public final void quack() {
if(quack != null) { // 如果quack不为null,就调用quack的quack()方法
quack.quack();
return;
}
System.out.println("鸭子会叫"); // 程序执行到此,说明quack为null
}
/**
* 游泳的方法
*/
public final void swim() {
if(swim != null) { // 如果swim不为null,就调用swim的swim()方法
swim.swim();
return;
}
System.out.println("鸭子会游泳"); // 程序执行到此,说明swim为null
}
public void setFly(FlyBehavior fly) {
this.fly = fly;
}
public void setQuack(QuackBehavior quack) {
this.quack = quack;
}
public void setSwim(SwimBehavior swim) {
this.swim = swim;
}
}
然后创建具体的使用类
(BeiJingDuck
、TangLaoDuck
、WildDuck
、ToyDuck
),这些类都继承上述的抽象类,如下:
package edu.hebeu.strategy.user;
import edu.hebeu.strategy.strategys.flybehavior.NotFlyBehavior;
import edu.hebeu.strategy.strategys.quackbehavior.GaGaQuackBehavior;
import edu.hebeu.strategy.strategys.swimbehavior.GoodSwimBehavior;
public class BeiJingDuck extends Duck{
public BeiJingDuck() {
fly = new NotFlyBehavior();
quack = new GaGaQuackBehavior();
swim = new GoodSwimBehavior();
}
@Override
public void display() {
System.out.println("------------------这是北京鸭-----------------");
fly();
quack();
swim();
System.out.println("---------------------------------------------");
}
}
package edu.hebeu.strategy.user;
import edu.hebeu.strategy.strategys.flybehavior.NotFlyBehavior;
import edu.hebeu.strategy.strategys.quackbehavior.GaGaQuackBehavior;
import edu.hebeu.strategy.strategys.swimbehavior.NotSwimBehavior;
public class TangLaoDuck extends Duck{
public TangLaoDuck() {
fly = new NotFlyBehavior();
quack = new GaGaQuackBehavior();
swim = new NotSwimBehavior();
}
@Override
public void display() {
System.out.println("------------------这是唐老鸭-----------------");
fly();
quack();
swim();
System.out.println("---------------------------------------------");
}
}
package edu.hebeu.strategy.user;
import edu.hebeu.strategy.strategys.flybehavior.GoodFlyBehavior;
import edu.hebeu.strategy.strategys.quackbehavior.GeGeQuackBehavior;
import edu.hebeu.strategy.strategys.swimbehavior.GoodSwimBehavior;
public class WildDuck extends Duck{
public WildDuck() {
fly = new GoodFlyBehavior();
quack = new GeGeQuackBehavior();
swim = new GoodSwimBehavior();
}
@Override
public void display() {
System.out.println("------------------这是野鸭-----------------");
fly();
quack();
swim();
System.out.println("---------------------------------------------");
}
}
package edu.hebeu.strategy.user;
import edu.hebeu.strategy.strategys.flybehavior.NotFlyBehavior;
import edu.hebeu.strategy.strategys.quackbehavior.GeGeQuackBehavior;
import edu.hebeu.strategy.strategys.swimbehavior.BadSwimBehavior;
public class ToyDuck extends Duck{
public ToyDuck() {
fly = new NotFlyBehavior();
quack = new GeGeQuackBehavior();
swim = new BadSwimBehavior();
}
@Override
public void display() {
System.out.println("------------------这是玩具鸭-----------------");
fly();
quack();
swim();
System.out.println("---------------------------------------------");
}
}
此时策略模式就搭建完毕了,我们通过下面的测试类来使用一下上面的代码,并实现上述的需求,如下所示:
package edu.hebeu.strategy;
import java.util.Scanner;
import edu.hebeu.strategy.strategys.flybehavior.BadFlyBehavior;
import edu.hebeu.strategy.strategys.flybehavior.GoodFlyBehavior;
import edu.hebeu.strategy.strategys.flybehavior.NotFlyBehavior;
import edu.hebeu.strategy.strategys.quackbehavior.GaGaQuackBehavior;
import edu.hebeu.strategy.strategys.quackbehavior.GeGeQuackBehavior;
import edu.hebeu.strategy.strategys.quackbehavior.NotQuackBehavior;
import edu.hebeu.strategy.strategys.swimbehavior.BadSwimBehavior;
import edu.hebeu.strategy.strategys.swimbehavior.GoodSwimBehavior;
import edu.hebeu.strategy.strategys.swimbehavior.NotSwimBehavior;
import edu.hebeu.strategy.user.BeiJingDuck;
import edu.hebeu.strategy.user.TangLaoDuck;
import edu.hebeu.strategy.user.ToyDuck;
import edu.hebeu.strategy.user.WildDuck;
public class Client {
private static Scanner SCANNER = new Scanner(System.in);
private static String KEYWORD = null;
private static BeiJingDuck BEIJING_DUCK = new BeiJingDuck();
private static TangLaoDuck TANGLAO_DUCK = new TangLaoDuck();
private static WildDuck WILD_DUCK = new WildDuck();
private static ToyDuck TOY_DUCK = new ToyDuck();
public static void main(String[] args) {
while(true) {
System.out.println("1. 查看指定鸭子信息");
System.out.println("2. 修改鸭子信息");
System.out.println("3. 查看全部鸭子");
KEYWORD = SCANNER.next();
if (KEYWORD.equals("1")) {
selectDuckInfo();
} else if (KEYWORD.equals("2")) {
alterDuckInfo();
} else if (KEYWORD.equals("3")) {
BEIJING_DUCK.display();
TANGLAO_DUCK.display();
WILD_DUCK.display();
TOY_DUCK.display();
} else {
System.out.println("bye~~~~");
break;
}
}
}
/**
* 查询指定鸭子信息的方法
*/
public static void selectDuckInfo() {
while (true) {
System.out.println("b(北京鸭)");
System.out.println("t(唐老鸭)");
System.out.println("w(野鸭)");
System.out.println("toy(玩具鸭)");
KEYWORD = SCANNER.next();
if (KEYWORD.equals("b")) {
BEIJING_DUCK.display();
} else if (KEYWORD.equals("t")) {
TANGLAO_DUCK.display();
} else if (KEYWORD.equals("w")) {
WILD_DUCK.display();
} else if (KEYWORD.equals("toy")) {
TOY_DUCK.display();
} else {
System.out.println("quit--");
break;
}
}
}
/**
* 修改指定鸭子信息的方法
*/
public static void alterDuckInfo() {
while (true) {
System.out.println("b(北京鸭)");
System.out.println("t(唐老鸭)");
System.out.println("w(野鸭)");
System.out.println("toy(玩具鸭)");
System.out.println("其他退出");
System.out.println("选项直接选择序号即可");
KEYWORD = SCANNER.next();
if (KEYWORD.equals("b")) {
System.out.print("北京鸭的飞行能力:1. 非常好、2. 不好、3. 不会");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
BEIJING_DUCK.setFly(new GoodFlyBehavior());
} else if ("2".equals(KEYWORD)) {
BEIJING_DUCK.setFly(new BadFlyBehavior());
} else if ("3".equals(KEYWORD)) {
BEIJING_DUCK.setFly(new NotFlyBehavior());
}
System.out.print("北京鸭的游泳能力:1. 非常好、2. 不好、3. 不会");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
BEIJING_DUCK.setSwim(new GoodSwimBehavior());
} else if ("2".equals(KEYWORD)) {
BEIJING_DUCK.setSwim(new BadSwimBehavior());
} else if ("3".equals(KEYWORD)) {
BEIJING_DUCK.setSwim(new NotSwimBehavior());
}
System.out.print("北京鸭的怎么叫:1. 嘎嘎嘎~~~、2. 咯咯咯~~~、3. 不能叫");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
BEIJING_DUCK.setQuack(new GaGaQuackBehavior());
} else if ("2".equals(KEYWORD)) {
BEIJING_DUCK.setQuack(new GeGeQuackBehavior());
} else if ("3".equals(KEYWORD)) {
BEIJING_DUCK.setQuack(new NotQuackBehavior());
}
} else if (KEYWORD.equals("t")) {
System.out.print("唐老鸭的飞行能力:1. 非常好、2. 不好、3. 不会");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
TANGLAO_DUCK.setFly(new GoodFlyBehavior());
} else if ("2".equals(KEYWORD)) {
TANGLAO_DUCK.setFly(new BadFlyBehavior());
} else if ("3".equals(KEYWORD)) {
TANGLAO_DUCK.setFly(new NotFlyBehavior());
}
System.out.print("唐老鸭的游泳能力:1. 非常好、2. 不好、3. 不会");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
TANGLAO_DUCK.setSwim(new GoodSwimBehavior());
} else if ("2".equals(KEYWORD)) {
TANGLAO_DUCK.setSwim(new BadSwimBehavior());
} else if ("3".equals(KEYWORD)) {
TANGLAO_DUCK.setSwim(new NotSwimBehavior());
}
System.out.print("唐老鸭的怎么叫:1. 嘎嘎嘎~~~、2. 咯咯咯~~~、3. 不能叫");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
TANGLAO_DUCK.setQuack(new GaGaQuackBehavior());
} else if ("2".equals(KEYWORD)) {
TANGLAO_DUCK.setQuack(new GeGeQuackBehavior());
} else if ("3".equals(KEYWORD)) {
TANGLAO_DUCK.setQuack(new NotQuackBehavior());
}
} else if (KEYWORD.equals("w")) {
System.out.print("野鸭的飞行能力:1. 非常好、2. 不好、3. 不会");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
WILD_DUCK.setFly(new GoodFlyBehavior());
} else if ("2".equals(KEYWORD)) {
WILD_DUCK.setFly(new BadFlyBehavior());
} else if ("3".equals(KEYWORD)) {
WILD_DUCK.setFly(new NotFlyBehavior());
}
System.out.print("野鸭的游泳能力:1. 非常好、2. 不好、3. 不会");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
WILD_DUCK.setSwim(new GoodSwimBehavior());
} else if ("2".equals(KEYWORD)) {
WILD_DUCK.setSwim(new BadSwimBehavior());
} else if ("3".equals(KEYWORD)) {
WILD_DUCK.setSwim(new NotSwimBehavior());
}
System.out.print("野鸭的怎么叫:1. 嘎嘎嘎~~~、2. 咯咯咯~~~、3. 不能叫");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
TANGLAO_DUCK.setQuack(new GaGaQuackBehavior());
} else if ("2".equals(KEYWORD)) {
TANGLAO_DUCK.setQuack(new GeGeQuackBehavior());
} else if ("3".equals(KEYWORD)) {
TANGLAO_DUCK.setQuack(new NotQuackBehavior());
}
} else if (KEYWORD.equals("toy")) {
System.out.print("玩具鸭的飞行能力:1. 非常好、2. 不好、3. 不会");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
TOY_DUCK.setFly(new GoodFlyBehavior());
} else if ("2".equals(KEYWORD)) {
TOY_DUCK.setFly(new BadFlyBehavior());
} else if ("3".equals(KEYWORD)) {
TOY_DUCK.setFly(new NotFlyBehavior());
}
System.out.print("玩具鸭的游泳能力:1. 非常好、2. 不好、3. 不会");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
TOY_DUCK.setSwim(new GoodSwimBehavior());
} else if ("2".equals(KEYWORD)) {
TOY_DUCK.setSwim(new BadSwimBehavior());
} else if ("3".equals(KEYWORD)) {
TOY_DUCK.setSwim(new NotSwimBehavior());
}
System.out.print("玩具鸭的怎么叫:1. 嘎嘎嘎~~~、2. 咯咯咯~~~、3. 不能叫");
KEYWORD = SCANNER.next();
if ("1".equals(KEYWORD)) {
TOY_DUCK.setQuack(new GaGaQuackBehavior());
} else if ("2".equals(KEYWORD)) {
TOY_DUCK.setQuack(new GeGeQuackBehavior());
} else if ("3".equals(KEYWORD)) {
TOY_DUCK.setQuack(new NotQuackBehavior());
}
}
System.out.println("quit--");
break;
}
}
}
测试