java策略模式 动态_Java 设计模式之策略模式

本文详细介绍了Java中的策略模式,包括模式定义、组成结构、UML图解和应用场景。通过模拟鸭子游戏的例子,展示了如何使用策略模式解决行为变化的问题,以避免过度使用继承和接口导致的代码冗余和灵活性降低。文章还探讨了策略模式的优缺点,强调了它在动态改变算法和避免多重条件转移语句方面的优势。
摘要由CSDN通过智能技术生成

一、了解策略模式

1.1 什么是策略模式

策略模式 (Strategy Pattern) 是指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换。此模式让算法的变化独立于使用算法的客户。

1.2 策略模式组成结构

环境 (Context):持有一个策略类的引用,最终给客户端调用。

抽象策略 (Strategy): 策略类,通常是一个接口或者抽象类。

具体策略 (ConcreteStrategy):实现了策略类中的策略方法,封装相关的算法和行为。

1.3 策略模式 UML 图解

e78a77da4134c19027b213b75a23a4af.png

1.4 策略模式应用场景

多个类只区别在表现行为不同,可以使用 Strategy 模式,在运行时动态选择具体要执行的行为。

需要在不同情况下使用不同的策略 (算法),或者策略还可能在未来用其它方式来实现。

对客户隐藏具体策略 (算法) 的实现细节,彼此完全独立。

二、策略模式具体应用

2.1 问题描述

模拟鸭子游戏:游戏中会出现各种鸭子,一边游泳戏水、一边呱呱叫,为了提高游戏的乐趣,加入了让鸭子飞的功能。但是考虑到并不是所有的鸭子都会飞,比如像小孩子游泳时玩的橡皮鸭。现在让你利用 OO 技术,设计鸭子相关的类。

2.2 使用继承

c3a5f68b98b9a1033d396ccd84267ad4.png

我们可能想到使用继承,在超类 Duck 中定义鸭子的相关方法,并实现其对应的动作,这样就能让所有鸭子都可以对应其 fly() 的动作。在定义橡皮鸭时,只需要覆盖其父类 (Duck) 中的 fly() 方法即可。

如果我们还想加入诱饵鸭,这种鸭子既不会叫,也不会飞,那么我们就要继承 Duck 类,重写其中的 quack() 、display() 和 fly() 方法。

52d537715694dbfad2381ae046750d70.png

这种通过继承的方法是可以解决问题,但是有很多的局限

代码在多个子类中重复。

运行时的行为不容易改变。

很难知道鸭子的全部行为。

改变会牵一发动全身,造成其他鸭子不想要的改变。

2.3 使用接口

1348010ee3c7f6699589c59fd8f2d693.png

认识到上面继承的不足,我们可能想到了另一种方式去解决这种问题,通过接口的方式去实现某些动作。把 fly() 和 quack() 方法从 Duck 类中抽取抽取出来,分别放在 Flyable 和 Quackable 接口中。

通过接口的方式是可以完成任务,但是这也确实是一个很笨的方式。因为对于很多种鸭子来说,它们大部分都会飞与呱呱叫,但是我们在定义它们类的时候都要去实现 Flyable 和 Quackable 接口,这样一来重复的代码更多了。

2.4 问题归零

到这里我们知道使用继承并不能很好的解决问题,因为鸭子的行为在子类中是不断变化的,并且让所有的鸭子都具有这些行为是不恰当的,比如橡皮鸭不具有飞的行为。通过接口的方式似乎还不错,但是 Java 接口并不具备实现代码,所以继承接口并不能达到代码复用的目的,一不小心,就可能造成新的错误!

幸运的是,有一个设计原则,恰好适用于这种状况:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。这样以来,代码变化引起的后果变少,系统将更有弹性。

2.5 策略模式登场

除了 fly() 和 quack() 方法之外,Duck 中的其他方法还算一切正常,没有什么需要经常需要变化或修改的地方。所以除了 fly() 和 quack() 方法,我们不打算对 Duck 中的其他方法做太多处理。我们希望一切具有弹性,正是因为没有弹性,上面两种方法都被我们淘汰掉了。

比如说,我们要产生一个绿头鸭的实例,并制定特定“类型”的飞行行为给它。我们可以在鸭子类中包含设定行为的方法,这样就可以在“运行时”动态地“改变”绿头鸭的飞行行为。

有了这些实现目标,于是就有了第二个设计原则:针对接口编程,而不是针对实现编程。

这里我们使用接口代表每个行为,比如说,FlyBehavior 与 QuackBehavior,而行为的每个实现都将实现其中一个接口。所以这次鸭子类不会去实现 Flyable 和 Quackable 接口,反而是由我们制造一组其他类专门实现 FlyBehavior 与 QuackBehavior,这就称为“行为”类。由行为类而不是 Duck 类来实现该接口。

(1)策略模式设计图

648a7ca34a17bfaf0961110aaba063b3.png

改造原来的鸭子类

001cae61838be165fc081fd78e77901d.png

(2) 代码实现

这里我们将 Duck 类定义成抽象类,并把 display() 方法定义成抽象方法。

接口 QuackBehavior

package com.jas.strategy;

public interface QuackBehavior {

void quack();

}

接口 QuackBehavior 实现类 Quack(实现鸭子呱呱叫)

package com.jas.strategy;

public class Quack implements QuackBehavior {

@Override

public void quack() {

System.out.println("Quack!");

}

}

接口 QuackBehavior 实现类 SQuack(实现鸭子橡皮吱吱叫)

package com.jas.strategy;

public class SQuack implements QuackBehavior {

@Override

public void quack() {

System.out.println("SQuack!");

}

}

接口 QuackBehavior 实现类 MuteQuack(实现鸭子不会叫)

package com.jas.strategy;

public class MuteQuack implements QuackBehavior {

@Override

public void quack() {

System.out.println("Silence!");

}

}

接口 FlyBehavior

package com.jas.strategy;

public interface FlyBehavior {

void fly();

}

接口 FlyBehavior 实现类 FlyWithWings(实现鸭子飞)

package com.jas.strategy;

public class FlyWithWings implements FlyBehavior {

@Override

public void fly() {

System.out.println("I'm flying!");

}

}

接口 FlyBehavior 实现类 FlyNoWay(实现鸭子不会飞)

package com.jas.strategy;

public class FlyNoWay implements FlyBehavior {

@Override

public void fly() {

System.out.println("I can't fly!");

}

}

Duck 类

package com.jas.strategy;

public abstract class Duck {

private QuackBehavior quackBehavior;

private FlyBehavior flyBehavior;

public void swim(){

System.out.println("All ducks float.");

}

public abstract void display();

public void performQuack(){

quackBehavior.quack();

}

public void performFly(){

flyBehavior.fly();

}

public void setQuackBehavior(QuackBehavior quackBehavior){

this.quackBehavior = quackBehavior;

}

public void setFlyBehavior(FlyBehavior flyBehavior){

this.flyBehavior = flyBehavior;

}

}

测试类 RubberDuck

package com.jas.strategy;

public class RubberDuck extends Duck {

@Override

public void display() {

System.out.println("Rubber Duck");

}

public static void main(String[] args) {

Duck rubberDuck = new RubberDuck(); //橡皮鸭实例

rubberDuck.setQuackBehavior(new SQuack()); //橡皮鸭吱吱叫

rubberDuck.setFlyBehavior(new FlyNoWay()); //橡皮鸭不会飞

rubberDuck.performQuack();

rubberDuck.performFly();

}

}

//输出

//SQuack!

//I can't fly!

2.6 从策略模式组成结构对问题进行总结

8b530f7d28a80ecf982352097224f6dc.png

三、策略模式总结

3.1 策略模式的优缺点

优点

策略模式提供了管理相关的算法族的办法,从而避免重复的代码。

策略模式提供了可以替换继承关系的办法。因为继承使得动态改变算法或行为变得不可能。

使用策略模式可以避免使用多重条件转移语句。

缺点

客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

策略模式造成很多的策略类,每个具体策略类都会产生一个新类。

四、参考资料

《Head First 设计模式》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值