策略模式
1. 基本介绍
- 策略模式,定义了算法族并分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
- 该模式体现了几个设计原则:
- 开闭原则:把变化的代码从不变的代码中分离出来;
- 依赖倒转原则:针对接口编程而不是具体的类;
- 合成复用原则:多使用组合/聚合,少使用继承。
2. 策略模式原理类图
3. 场景设定
编写鸭子项目:
- 有各自鸭子【野鸭、水鸭、小黄鸭、北京烤鸭】
- 各种鸭子的行为【飞、叫、飞行、游泳】
- 显示鸭子信息
4. 策略模式解决鸭子项目
4.1 思路分析
- 分别封装行为接口,实现算法族。超类里放置接口对象,在子类中设置具体的行为对象。
- 原则:分离变化部分,并封装成接口,基于接口编写具体细节,让行为的变化独立于算法的使用者。
- 类图如下:
4.2 FlyBehavior接口及其实现
/**
* @author: zipeng Li
* 2021/5/22 10:14
*/
public interface FlyBehavior {
void fly();
}
/**
* @author: zipeng Li
* 2021/5/22 10:14
*/
public class GoodFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("我是飞行小能手。。。");
}
}
/**
* @author: zipeng Li
* 2021/5/22 10:06
*/
public class NoFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("我不会飞呀。。。");
}
}
4.3 QuackBehavior接口及其实现
/**
* @author: zipeng Li
* 2021/5/22 10:19
*/
public interface QuackBehavior {
void quack();
}
/**
* @author: zipeng Li
* 2021/5/22 10:17
*/
public class GagaQuackBehavior implements QuackBehavior{
@Override
public void quack() {
System.out.println("嘎嘎嘎嘎嘎嘎。。。。。");
}
}
/**
* @author: zipeng Li
* 2021/5/22 10:17
*/
public class HahaQuackBehavior implements QuackBehavior{
@Override
public void quack() {
System.out.println("hahahahhahaha...");
}
}
4.4 Duck抽象及其实现
/**
* @author: zipeng Li
* 2021/5/22 10:18
*/
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
public void fly(){
if(flyBehavior != null){
flyBehavior.fly();
}
}
public void quack(){
if(quackBehavior != null){
quackBehavior.quack();
}
}
public abstract void display();
}
/**
* @author: zipeng Li
* 2021/5/22 10:26
*/
public class PekingDuck extends Duck {
public PekingDuck() {
quackBehavior = new HahaQuackBehavior();
flyBehavior = new NoFlyBehavior();
}
@Override
public void display() {
System.out.println("我是北京烤鸭。。。");
}
}
/**
* @author: zipeng Li
* 2021/5/22 10:29
*/
public class WildDuck extends Duck {
public WildDuck() {
flyBehavior = new GoodFlyBehavior();
quackBehavior = new GagaQuackBehavior();
}
@Override
public void display() {
System.out.println("我是野鸭呀。。。");
}
}
4.5 客户端测试
/**
* @author: zipeng Li
* 2021/5/22 10:31
*/
public class Client {
public static void main(String[] args) {
PekingDuck pekingDuck = new PekingDuck();
pekingDuck.display();
pekingDuck.quack();
pekingDuck.fly();
System.out.println("===================");
WildDuck wildDuck = new WildDuck();
wildDuck.display();
wildDuck.fly();
wildDuck.quack();
// 动态改变
wildDuck.setFlyBehavior(new NoFlyBehavior());
wildDuck.fly();
}
}
我是北京烤鸭。。。
hahahahhahaha...
我不会飞呀。。。
===================
我是野鸭呀。。。
我是飞行小能手。。。
嘎嘎嘎嘎嘎嘎。。。。。
我不会飞呀。。。
5. 策略模式在JDK-Arrays的应用
JDK 的 Arrays 的 Comparator 使用了策略模式
/**
* @author: zipeng Li
* 2021/5/22 10:46
*/
public class Strategy {
public static void main(String[] args) {
Integer[] data = {9, 1, 2, 8, 4, 3};
/**
* 1. Comparator 为策略接口,new Comparator<Integer>(){} 就是实现了策略接口的对象
* 2. public int compare(Integer o1, Integer o2) {}方法则指定了具体的处理方法
*/
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
if (o1 > o2) {
return 1;
} else {
return -1;
}
}
};
Arrays.sort(data, comparator);
System.out.println(Arrays.toString(data));
}
}
// 根据传入的具体策略对象 c 进行相应排序
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);
}
}
6. 总结
- 优点:通过分析需求中的变与不变的部分,对变化的部分进行策略接口封装,其实现交由具体的子类。后期需要添加新的策略,则只需要添加新的类,而不用修改原有代码,体现了开闭原则。
- 缺点:每添加一种策略就需要新建一个类,会造成类过多的局面。
后序
- 我是一名大三本科生,专业是软件工程【一本】。目前,正在准备找实习以及秋招,意向岗位是Java后端开发工程师。为此,在码云托管了一个项目,以整理我所有所学知识。涉及内容:计算机网络、操作系统、Java基础、主流Java后端框架、设计模式、Web前端框架等内容。欢迎大家访问我的开源项目编程之路
- 码云地址:https://gitee.com/alizipeng/the-way-of-programming
- 以上内容均记载在我的开源项目中