假设接到设计僵尸大战中僵尸角色,当前只有普通僵尸和棋手僵尸
抽象僵尸的公共行为
public abstract class AbstractZombie {
abstract void display();
abstract void move();
abstract void attack();
}
普通僵尸
public class NormalZombie extends AbstractZombie {
@Override
void display() {
System.out.println("普通僵尸");
}
@Override
void move() {
System.out.println("每次移动一步");
}
@Override
void attack() {
System.out.println("咬");
}
}
棋手僵尸
public class FlagZombie extends AbstractZombie {
@Override
void display() {
System.out.println("普通僵尸+旗帜");
}
@Override
void move() {
System.out.println("每次移动一步");
}
@Override
void attack() {
System.out.println("咬");
}
}
测试:
public class StrategyTest {
public static void main(String[] args) {
NormalZombie normalZombie = new NormalZombie();
normalZombie.display();
normalZombie.move();
normalZombie.attack();
}
}
如果此时产品经理说僵尸在吃到豌豆后,需要加快移动或者改变僵尸的显示方式或者攻击的方式,是不是得改动存量代码?很难维护?这种hard coding力不从心。
此时引入策略模式就是很好的选择,将各种行为抽象为一个个接口,并定义一个个具体的行为类(即策略),抽象僵尸包含这些策略接口,具体策略来执行具体的行为。
定义
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式的变化独立于算法的使用者。
策略模式改造
- 抽象攻击方式和定义具体的攻击策略
public interface Attack {
void attack();
}
public class BiteAttack implements Attack {
@Override
public void attack() {
System.out.println("攻击方式:咬");
}
}
public class HeadAttack implements Attack {
@Override
public void attack() {
System.out.println("攻击方式:头撞击");
}
}
- 抽象移动方式和定义具体的移动策略
public interface Attack {
void attack();
}
public class OneStepMovable implements Movable {
@Override
public void move() {
System.out.println("每次移动一步");
}
}
public class TwoStepMovable implements Movable {
@Override
public void move() {
System.out.println("每次移动两步");
}
}
- 改造抽象僵尸
public abstract class AbstractZombie {
Movable movable;
Attack attack;
AbstractZombie() {
this(new OneStepMovable(), new BiteAttack());
}
AbstractZombie(Movable movable, Attack attack) {
this.movable = movable;
this.attack = attack;
}
public void setMovable(Movable movable) {
this.movable = movable;
}
public void setAttack(Attack attack) {
this.attack = attack;
}
abstract void display();
abstract void move();
abstract void attack();
}
- 测试
public class StrategyTest {
public static void main(String[] args) {
NormalZombie normalZombie = new NormalZombie();
normalZombie.display();
normalZombie.move();
normalZombie.attack();
// 使僵尸在运行过程中动态修改移动方式和攻击方式
normalZombie.setMovable(new TwoStepMovable());
normalZombie.move();
normalZombie.setAttack(new HeadAttack());
normalZombie.attack();
}
}
应用场景
- 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
- 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
- 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
源码级应用
-
Spring源码
策略接口:org.springframework.beans.factory.support.InstantiationStrategy
具体策略:CglibSubclassingInstantiationStrategy和SimpleInstantiationStrategy
该策略表示在Spring框架中AbstractAutowireCapableBeanFactory使用哪种方式实例化bean对象;第一种是cglib代理创建对象,第二种是通过普通的newInstance创建实例。 -
JDK源码
策略接口:java.util.Comparator
Comparator应用非常广泛,有很多策略实现。例如:Spring实现的OrderComparator,用来实现排序的,等等
也可自定义实现:
public class MyComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
public static void main(String[] args) {
// 比较两个数的大小
Integer i1 = 1;
Integer i2 = 2;
MyComparator comparator = new MyComparator();
System.out.println(comparator.compare(i1, i2) < 0);
}
}