参考:head-first-设计模式
定义
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的用户
光看定义有点懵逼,接下使用代码一步步改进,慢慢形成策略模式
看完相信你会对策略模式有所了解
项目结构
类图
问题描述
一般鸭子的行为分为游泳,外形,飞,叫
游泳和外形是每个鸭子都有的,而飞和叫不是都有
我们一般实现都是直接写Duck抽象类,然后申明这4个方法
public abstract class Duck {
public abstract void flly();
public abstract void quack();
public abstract void swim();
public abstract void display();
}
然后具体鸭子类继承Duck类,实现这4个方法
但是有些鸭子不会飞,比如橡皮鸭,有些不会叫,比如木头鸭
这样每个鸭子都实现了飞和叫的方法,就会产生很多无用的代码
改进一下
申明两个接口flyable和quackable,分别申明fly和quack方法
会飞的鸭子才实现flyable的接口
会叫的鸭子才实现quackable接口
这样就解决了不能飞的鸭子还要实现fly()方法的问题
但是这样也有问题
所有会飞的鸭子都要实现fly()方法,当两个鸭子fly的方式相同时,两个fly的实现差不多,这样就会产生很多重复的代码,实现类不能够复用
再改进一下
申明两个接口FlyBehavior和QuackBehavior,分别申明fly和quack方法
public interface FlyBehavior {
void fly();
}
public interface QuackBehavior {
void quack();
}
根据行为的不同,分别实现这两个接口
飞两种形态
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("FlyNoWay");
}
}
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("FlyWithWings");
}
}
叫三种形态
public class MuteQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("MuteQuack");
}
}
public class Quack implements QuackBehavior {
@Override
public void quack() {
System.out.println("Quack");
}
}
public class Squack implements QuackBehavior {
@Override
public void quack() {
System.out.println("Squack");
}
}
然后在Duck类中申明这两个接口,接口编写执行行为的方法,performFly和performQuack
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
public abstract void swim();
public abstract void display();
}
测试一下,看看如何使用
首先编写一个鸭子的具体实现类,在构造方法中指明使用的是哪个形态的飞和叫
public class MallardDuck extends Duck {
@Override
public void swim() {
System.out.println("swim");
}
@Override
public void display() {
System.out.println("green");
}
public MallardDuck() {
flyBehavior = new FlyWithWings();
quackBehavior = new Quack();
}
}
接着写测试代码
@RunWith(SpringRunner.class)
@SpringBootTest
public class celueDemoApplicationTests {
@Test
public void contextLoads() {
Duck duck = new MallardDuck();
duck.performFly();
duck.performQuack();
}
}
结果展示,控制台打印
这种方式必须在实现具体鸭子的时候在构造方法中指明是哪种方式,所以还是有点问题
再改进一下
在Duck类中新增方法setQuack和setFly,如下所示
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
public void setQuack(QuackBehavior quackBehavior){
this.quackBehavior=quackBehavior;
}
public void setFly(FlyBehavior fly){
this.flyBehavior = fly;
}
public abstract void swim();
public abstract void display();
}
这样就能在代码运行中随时修改飞和叫的形式
测试使用一下
@RunWith(SpringRunner.class)
@SpringBootTest
public class celueDemoApplicationTests {
@Test
public void contextLoads() {
Duck duck = new MallardDuck();
duck.performFly();
duck.performQuack();
//修改飞的形式为不能飞
duck.setFly(new FlyNoWay());
//修改呱呱叫为吱吱叫
duck.setQuack(new Squack());
duck.performFly();
duck.performQuack();
}
}
结果展示
这就是策略模式