策略模式,简单的来说就是针对接口编程,一个类的行为或其算法可以在运行时更改。
策略模式主要解决:一种类型有多种情况,使用 if...else 所带来的复杂和难以维护。
如何解决:将这些算法封装成一个一个的类,任意地替换。 关键代码:实现同一个接口。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。 注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
为什么不使用继承而使用策略模式:继承在编写时已经定型了具体的实现,而策略模式,则是在运行时动态的加载实现。
写一个特别简单的例子,针对两个数的操作,可以是加减乘除等等操作,那么,就先创建一个两个数值操作的接口
package lcl.mm.pattern.stretegy.demo2;
public interface OperationInterface {
public int doOperation(int num1, int num2);
}
针对该接口,编写具体的实现类,这里为了演示,只写两个加减法的实现
package lcl.mm.pattern.stretegy.demo2;
public class OperationAdd implements OperationInterface {
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
package lcl.mm.pattern.stretegy.demo2;
public class OperationSub implements OperationInterface {
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
测试方法
@Test
void strategyTest2() {
int num1 = 10;
int num2 = 5;
OperationInterface operation = new OperationSub();
log.info("new OperationSub()====={}",operation.doOperation(num1,num2));
operation = new OperationAdd();
log.info("new OperationAdd()====={}",operation.doOperation(num1,num2));
}
输出
然后再写一个稍微复杂点的例子,有一个鸭子类,鸭子类里面有叫的方法quack,飞行的方法fly,游泳的方法swim,由于有的鸭子会叫,有的不会叫,有的会飞,有的不会飞,有的会游泳,有的不会游泳。那么如果使用继承,那么所有的鸭子子类,都需要重写父类的这三个方法,去写自己的实现;而如果使用策略模式,则可以针对写两个接口,分别为飞行的接口FlyBehavior和叫的接口QuackBehavior,根据不同的行为,创建对应不同的实现类,比如,针对飞行的接口FlyBehavior创建可飞行实现类FlyImpl和不可飞行实现类NoflyImpl,针对叫的接口分别创建会叫的实现类QuackImpl和NoQuackImpl,而Duck类中,引入飞行的接口FlyBehavior和叫的接口QuackBehavior,直接调用这两个接口中的叫方法quack和飞行方法fly,后续每添加一个鸭子,只需要在其构造方法中针对设置指定的飞行接口FlyBehavior的实现类和叫的接口QuackBehavior的实现类即可。
下面就模拟一下上述例子:
创建飞行的接口FlyBehavior和叫的接口QuackBehavior
package lcl.mm.pattern.stretegy; public interface FlyBehavior { public void fly(); }
package lcl.mm.pattern.stretegy; public interface QuackBehavior { public void quack(); }
创建FlyBehavior接口的两个实现类
package lcl.mm.pattern.stretegy; import lombok.extern.slf4j.Slf4j; @Slf4j public class NoflyImpl implements FlyBehavior{ @Override public void fly() { log.info("I can't fly"); } }
package lcl.mm.pattern.stretegy; import lombok.extern.slf4j.Slf4j; @Slf4j public class FlyImpl implements FlyBehavior { @Override public void fly() { log.info("i can fly"); } }
创建QuackBehavior接口的实现类
package lcl.mm.pattern.stretegy; import lombok.extern.slf4j.Slf4j; @Slf4j public class QuackImpl implements QuackBehavior { @Override public void quack() { log.info("I can quack"); } }
package lcl.mm.pattern.stretegy; import lombok.extern.slf4j.Slf4j; @Slf4j public class NoQuackImpl implements QuackBehavior{ @Override public void quack() { log.info("I can't quack"); } }
创建鸭子主类
package lcl.mm.pattern.stretegy; import lombok.extern.slf4j.Slf4j; @Slf4j public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public abstract void display(); public void performFly(){ flyBehavior.fly(); } public void performQuack(){ quackBehavior.quack(); } public void swim(){ log.info("All duck float"); } }
下面就创建两个不同的具体鸭子实现
package lcl.mm.pattern.stretegy; import lombok.extern.slf4j.Slf4j; @Slf4j public class MallardDuck extends Duck { public MallardDuck(){ quackBehavior = new QuackImpl(); flyBehavior = new FlyImpl(); } @Override public void display() { log.info("I'm mallard duck!"); } }
package lcl.mm.pattern.stretegy; import lombok.extern.slf4j.Slf4j; @Slf4j public class SqueakDuck extends Duck{ public SqueakDuck(){ flyBehavior = new FlyImpl(); quackBehavior = new NoQuackImpl(); } @Override public void display() { log.info("I'm Squeak Duck"); } }
最终,添加测试类
@Test void strategyTest() { Duck duck = new MallardDuck(); duck.display(); duck.swim(); duck.performFly(); duck.performQuack(); duck = new SqueakDuck(); duck.display(); duck.swim(); duck.performFly(); duck.performQuack(); }
测试结果: