策略模式
模式定义:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式的变化独立于算法的使用者。
案例:
类图如下:

如上所示,类图中抽象类定义了 三个抽象方法,分别对应三个动作:移动,攻击,展示,两个策略属性:攻击策略,移动策略。在具体的实现类(NormalZombie,FlagZombie,BigHeadZombie)中攻击和移动方法
使用了策略模式,具体攻击和移动方式,由策略属性的方法决定。可根据实际需要,对攻击和移动策略进行更换。
import lombok.AllArgsConstructor; import lombok.Data; /** * 定义策略模式,使用类 */ public class StartNew { public static void main(String[] args) { AbstractZombie zombie = new NormalAbstractZombie(); /* 原来行为: 外表展示,攻击手段,移动方式 */ zombie.display(); zombie.move(); System.out.println("------原始攻击策略------"); zombie.attack(); /* 更改攻击策略,使用已经定义的攻击策 */ System.out.println("------第一次,更换攻击策略------"); zombie.setAttackableStrategy(new HitAttack()); zombie.attack(); /* 再次更改攻击行为策略,使用匿名类添加没有的攻击策略 */ System.out.println("------第二次,更换攻击策略------"); zombie.setAttackableStrategy(new AttackableStrategy() { @Override public void attack() { System.out.println("匿名类自定义攻击策略:撕咬挠,全上!!!"); } }); /// 以上代码是为了说清楚,其实可用lambda简化: /// zombie.setAttackableStrategy(() -> System.out.println("撕咬挠,全上!!!")); zombie.attack(); } } /** * 定义移动策略接口, 包含方法有move()方法 */ interface MoveableStrategy { void move(); } /** * 定义攻击策略接口, 包含方法有attack()方法 */ interface AttackableStrategy { void attack(); } /** * 僵尸(核心业务)抽象类 * 整体抽象业务轮廓,定义公共属性、实现可共享方法,列出需要个性化的抽象方法 */ @Data @AllArgsConstructor abstract class AbstractZombie { /** 移动策略对象 */ MoveableStrategy moveableStrategy; /** 攻击策略对象 */ AttackableStrategy attackableStrategy; /** * 展示 */ abstract void display(); /** * 移动 */ abstract void move(); /** * 攻击 */ abstract void attack(); } /** * 普通僵尸 * 定义抽象对象的名称,完成具体方法的重写 */ class NormalAbstractZombie extends AbstractZombie { public NormalAbstractZombie() { super(new StepByStepMove(), new BiteAttack()); } public NormalAbstractZombie(MoveableStrategy moveable, AttackableStrategy attackable) { super(moveable, attackable); } /** * 外观展现 * 不变的内容,固定在具体实现类中 */ @Override public void display() { System.out.println("我是普通僵尸."); } /** * 移动 * 属于策略模式中变的内容,留在移动策略实现类里实现,完成侧率变化 */ @Override void move() { moveableStrategy.move(); } /** * 攻击 * 属于策略模式中变的内容,留在攻击策略实现类里实现,完成侧率变化 */ @Override void attack() { attackableStrategy.attack(); } } /** * 大头僵尸 * 定义抽象对象的名称,完成具体方法的重写 */ class BigHeadZombie extends AbstractZombie { public BigHeadZombie() { super(new StepByStepMove(), new BiteAttack()); } public BigHeadZombie(MoveableStrategy moveable, AttackableStrategy attackable) { super(moveable, attackable); } /** * 外观展现 * 不变的内容,固定在具体实现类中 */ @Override public void display() { System.out.println("我是大头僵尸."); } /** * 移动 * 属于策略模式中变的内容,留在移动策略实现类里实现,完成侧率变化 */ @Override void move() { moveableStrategy.move(); } /** * 攻击 * 属于策略模式中变的内容,留在攻击策略实现类里实现,完成侧率变化 */ @Override void attack() { attackableStrategy.attack(); } } /** * 骑手僵尸 * 定义抽象对象的名称,完成具体方法的重写 */ class FlagZombie extends AbstractZombie { public FlagZombie() { super(new StepByStepMove(), new BiteAttack()); } public FlagZombie(MoveableStrategy moveable, AttackableStrategy attackable) { super(moveable, attackable); } /** * 外观展现 * 不变的内容,固定在具体实现类中 */ @Override public void display() { System.out.println("我是旗手僵尸."); } /** * 移动 * 属于策略模式中变的内容,留在移动策略实现类里实现,完成侧率变化 */ @Override void move() { moveableStrategy.move(); } /** * 攻击 * 属于策略模式中变的内容,留在攻击策略实现类里实现,完成侧率变化 */ @Override void attack() { attackableStrategy.attack(); } } /** * 滚动走 * 移动方式实现类, 具体实现 move() 方法 */ class RollMove implements MoveableStrategy { @Override public void move() { System.out.println("系统定义好的移动策略实现:滚动"); } } /** * 一步一步走 * 移动方式实现类, 具体实现 move() 方法 */ class StepByStepMove implements MoveableStrategy { @Override public void move() { System.out.println("系统定义好的移动策略实现:一步一步移动"); } } /** * 口咬 * 攻击方式实现类, 具体实现 attack() 方法 */ class BiteAttack implements AttackableStrategy { @Override public void attack() { System.out.println("系统定义好的攻击策略实现:嘴咬"); } } /** * 用手打 * 第二种攻击方式实现类, 具体实现 attack() 方法 */ class HitAttack implements AttackableStrategy { @Override public void attack() { System.out.println("系统定义好的攻击策略实现:手打"); } }
结果:
我是普通僵尸. 系统定义好的移动策略实现:一步一步移动 ------原始攻击策略------ 系统定义好的攻击策略实现:嘴咬 ------第一次,更换攻击策略------ 系统定义好的攻击策略实现:手打 ------第二次,更换攻击策略------ 匿名类自定义攻击策略:撕咬挠,全上!!!
应用场景:
1.当你有很多类似的类,但它们执行某些行为的方式不同时,请使用此策略。
2.使用该模式将类的业务逻辑与算法的实现细节隔离开来,这些算法在逻辑上下文中可能不那么重要。
3.当你的类具有大量的条件运算符,并且在同一算法的不同变体之间切换时,请使用此模式。
优点:
1.可以将算法的实现细节与使用它的代码隔离开来。
2.符合开闭原则
Spring & JDK 源码中的应用:
1 java.util.Comparator
根据数组对象,灵活制定排序策略
public class CompareTest491 { @Test public void test1(){ String[] arr = new String[]{"AA","MM","GG","DD","KK","CC"}; //将上述字符串数组从大到小排 //由于默认的Arrays.sort()是调用String的compareTo()方法的(String实现了Comparable接口),而String的compareTo()方法是从小到大的, //要想临时进行一次从大到小的排序,可以在参数里面写一个Comparator的匿名实现类的匿名对象,然后重写compare方法,进而设置从大到小排 Arrays.sort(arr, new Comparator<String>() { @Override public int compare(String o1, String o2) { return -o1.compareTo(o2); } }); System.out.println(Arrays.toString(arr)); } @Test public void test2(){ Goods[] arr=new Goods[5]; arr[0] = new Goods("lenovoMouse",34); arr[1] = new Goods("dellMouse",43);
arr[2] = new Goods("xiaomiMouse",12);
arr[3] = new Goods("huaweiMouse",65);
arr[4] = new Goods("microsoftMouse",43);
//这时如果想按照名称从低到高排序,再按照价格从高到低排序 //由于Goods类中的compareTo()方法的排序和想要的排序方式不一样,因此我们可以使用定制的排序 //因此在Arrays.sort()参数中new一个Comparator并重写compare()方法,实现想要的排序方式 Arrays.sort(arr, new Comparator<Goods>() { @Override public int compare(Goods o1, Goods o2) { if (o1.getName().equals(o2.getName())){ return -Double.compare(o1.getPrice(),o2.getPrice());//前面有个负号,表示从高到低排序 //一般情况下,String、包装类等重写的compareTo()或compare()方法都是从小到大排序的,所以想要从大到小排序的话需要在前面加"-" } else { return o1.getName().compareTo(o2.getName()); } } }); System.out.println(Arrays.toString(arr)); } }
2 org.springframework.beans.factory.support.InstantiationStrategy
浙公网安备 33010602011771号