Java设计模式之 [21] 行为型模式 - 策略模式

简介

1.策略模式(Strategy Pattern) 中.定义算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户
2.这算法实现了几个设计原则,第一,把变化的代码从不变的代码中分离出来,第二,针对接口编程而不是具体类(定义了策略接口)第三,多用组合.聚合,少用继承(客户通过组合的方式使用策略)

原理类图
类图分析
说明:

从上图可以看,客户Context有成员变量 strategy获取其他的策略接口,至于需要使用那个策略,可以在构造器中指定

案例分析 鸭子项目

1.有各种各样的鸭子 然后鸭子有各种行为
2.显示鸭子的信息

传统方法分析
传统方法分析

1.类图分析


类图

2.代码实现

public abstract class Duck {

    public Duck() {
        
    }
    
    public void quack() {
        System.out.println("鸭子嘎嘎嘎嘎");
    }
    
    public void swim() {
        System.out.println("鸭子会游泳");
    }
    public void fly() {
        System.out.println("鸭子会飞");
    }
    
    public abstract void display();
}
public class WildDuck extends Duck {

    @Override
    public void display() {
        System.out.println("这是野鸭");
    }

}
public class ToyDuck extends Duck {

    @Override
    public void display() {
        System.out.println("玩具鸭子");
    }

    @Override
    public void quack() {
        System.out.println("不能叫");
    }

    @Override
    public void fly() {
        System.out.println("不能非");
    }

    @Override
    public void swim() {
        System.out.println("不能游戏");
    }
}
public class Client {
    public static void main(String[] args) {
        WildDuck duck = new WildDuck();
        duck.display();
    }
}

测试

这是野鸭
传统方法问题分析

1.其他鸭子,都继承了Duck类,所以fly类让所有的鸭子都会飞了,这是不正确的
2.上面说的1的问题,其实是继承带来的问题:对类的局部改动,尤其是超类的局部改动.会影响其他部分,会有溢出效应
3.为了改进1的问题,可以通过覆盖 fly 方法来解决 ==>> 覆盖解决
4.问题又来了,如果我们有一个玩具鸭子,ToyDuck 就需要覆盖所有的方法. 解决思路 ==>> 策略模式

策略模式实现类图分析与源码

1.类图分析 类图
策略模式:分别封装行为接口,实现算法族,超类里面放行为接口对象,在子类里面具体设定行为对象.原则就是:分离变化的部分,封装接口,基于接口编程各种功能.此模式让行为的变化独立于算法的使用者


类图分析

2.实现代码

public interface FlyBehavior {
    void fly();
}
public class GoodFlyBehavior implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println(" GoodFlyBehavior ");
    }

}
public class BadFlyBehavior implements FlyBehavior{

    @Override
    public void fly() {
        System.out.println(" BadFlyBehavior ");
    }

}
public class NoFlyBehavior implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println(" NoFlyBehavior ");
    }

}
public abstract class Duck {

    FlyBehavior flyBehavior;

    public Duck() {

    }

    public abstract void display();

    public void quack() {
        System.out.println("鸭子嘎嘎嘎嘎");
    }

    public void swim() {
        System.out.println("鸭子会游泳");
    }

    public void fly() {
        if (flyBehavior != null) {
            flyBehavior.fly();
        }
    }

    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

}
public class WildDuck extends Duck {

    public WildDuck() {
        flyBehavior = new GoodFlyBehavior();
    }

    @Override
    public void display() {
        System.out.println("这是野鸭");
    }

}
public class PekingDuck extends Duck {

    
    public PekingDuck() {
        flyBehavior = new BadFlyBehavior();
    }
    
    @Override
    public void display() {
        System.out.println("北京鸭子");
    }

}
public class ToyDuck extends Duck {

    public ToyDuck() {
        flyBehavior = new NoFlyBehavior();
    }

    @Override
    public void display() {
        System.out.println("玩具鸭子");
    }
}

测试

public class Client {
    public static void main(String[] args) {
        WildDuck duck = new WildDuck();
        duck.display();
        duck.fly();
        System.out.println("改变野鸭的飞行行为");
        duck.setFlyBehavior(new NoFlyBehavior());
        duck.fly();
        System.out.println("-------------------------");
        PekingDuck duck2 = new PekingDuck();
        duck2.display();
        duck2.fly();
        System.out.println("-------------------------");
        ToyDuck duck3 = new ToyDuck();
        duck3.display();
        duck3.fly();
    }
}

测试结果

这是野鸭
 GoodFlyBehavior 
改变野鸭的飞行行为
 NoFlyBehavior 
-------------------------
北京鸭子
 BadFlyBehavior 
-------------------------
玩具鸭子
 NoFlyBehavior 
策略模式在 JDK-Arrays 应用的源码分析

1.JDK 的 Arrays 的Comparator 就实现了策略模式
2.源码

public class TestStrategy {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        // 数组
        Integer[] data = { 9, 1, 2, 8, 4, 3 };
        // 实现降序排序,返回-1放左边,1放右边,0保持不变

        // 说明
        // 1. 实现了 Comparator 接口(策略接口) , 匿名类 对象 new Comparator<Integer>(){..}
        // 2. 对象 new Comparator<Integer>(){..} 就是实现了 策略接口 的对象
        // 3. public int compare(Integer o1, Integer o2){} 指定具体的处理方式
        Comparator<Integer> comparator = new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                if (o1 > o2) {
                    return -1;
                } else {
                    return 1;
                }
            };
        };

        // 说明
        /*
         * public static <T> void sort(T[] a, Comparator<? super T> c) { if (c == null)
         * { sort(a); //默认方法 } else { if (LegacyMergeSort.userRequested)
         * legacyMergeSort(a, c); //使用策略对象c else // 使用策略对象c TimSort.sort(a, 0, a.length,
         * c, null, 0, 0); } }
         */
        // 方式1
        Arrays.sort(data, comparator);

        System.out.println(Arrays.toString(data)); // 降序排序

        // 方式2- 同时lambda 表达式实现 策略模式
        Integer[] data2 = { 19, 11, 12, 18, 14, 13 };

        Arrays.sort(data2, (var1, var2) -> {
            if (var1.compareTo(var2) > 0) {
                return -1;
            } else {
                return 1;
            }
        });

        System.out.println("data2=" + Arrays.toString(data2));

    }

}

JDK源码

public interface Comparator<T> {
    int compare(T o1, T o2);
}
public class Arrays {
    public static <T> void sort(T[] a, Comparator<? super T> c) {
        if (c == null) {
            sort(a);
        } else {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }
}

lambda表达式 代码在上面测试部分

策略模式注意事项和细节

1.策略模式的关键是:分析项目中变化部分和不变部分
2.策略模式的核心思想是:多用组合/聚合 少用继承,用行为类组合,而不是行为的继承,更加有弹性
3.体现了"对修改关闭,对拓展开放"原则,客户端增加行为不同修改原有代码,只要添加一种策略(模式)即可,避免了使用多重转移语句(if - else -else if -else)
4.提供了可以替代继承关系的办法:策略模式将算法封装到独立的 Strategy 类中使得你可以独立与Context改变他,使得它易于切换,易于理解,易于拓展
5.需要注意的是:没添加一个策略都要增加一个类,当策略过多的时候会导致类数目庞大

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容