本文参考自: 《JAVA设计模式》之策略模式(Strategy)
1. 作用
策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
2. 结构
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。下面就以一个示意性的实现讲解策略模式实例的结构。
策略模式涉及到的三个角色
-
抽象的Strategy
这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。 -
具体的strategy
包装了相关的算法或行为。 -
客户端类Context
持有一个Strategy的引用。
3. 具体实现
抽象Strategy类
public interface AbstractStrategy {
void method();
}
具体的Strategy类
public class ConcreteStrategy1 implements AbstractStrategy {
@Override
public void method() {
System.out.println("this is strategy1");
}
}
public class ConcreteStrategy2 implements AbstractStrategy {
@Override
public void method() {
System.out.println("this is strategy2");
}
}
public class ConcreteStrategy3 implements AbstractStrategy {
@Override
public void method() {
System.out.println("this is strategy3");
}
}
客户端类
public class Context {
private AbstractStrategy strategy;
public Context(AbstractStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(AbstractStrategy strategy) {
this.strategy = strategy;
}
public void method() {
strategy.method();
}
}
实际调用
public class StrategyPatternMain {
public static void main(String[] args) {
AbstractStrategy strategy1 = new ConcreteStrategy1();
AbstractStrategy strategy2 = new ConcreteStrategy2();
AbstractStrategy strategy3 = new ConcreteStrategy3();
Context context = new Context(strategy1);
context.method();
context.setStrategy(strategy2);
context.method();
context.setStrategy(strategy3);
context.method();
}
}
4. 使用例子
假设现在要设计一个贩卖各类书籍的电子商务网站的购物车系统。一个最简单的情况就是把所有货品的单价乘上数量,但是实际情况肯定比这要复杂。比如,本网站可能对所有的高级会员提供每本20%的促销折扣;对中级会员提供每本10%的促销折扣;对初级会员没有折扣。
根据描述,折扣是根据以下的几个算法中的一个进行的:
算法一:对初级会员没有折扣。
算法二:对中级会员提供10%的促销折扣。
算法三:对高级会员提供20%的促销折扣。
使用策略模式来实现的结构图如下:
抽象Strategy类
public interface MemberStrategy {
String getType();
int calculatePrice(int originalPrice);
}
会员类
public class NormalMember implements MemberStrategy {
@Override
public String getType() {
return "normal member";
}
@Override
public int calculatePrice(int originalPrice) {
System.out.println("normal member has no discount");
return originalPrice;
}
}
public class MiddleMember implements MemberStrategy{
@Override
public String getType() {
return "middle member";
}
@Override
public int calculatePrice(int originalPrice) {
System.out.println("middle member discount is 10%");
return (int)(originalPrice*0.9);
}
}
public class HighMember implements MemberStrategy {
@Override
public String getType() {
return "high member";
}
@Override
public int calculatePrice(int originalPrice) {
System.out.println("high member discount is 20%");
return (int)(originalPrice*0.8);
}
}
价格类
public class Price {
private MemberStrategy memberStrategy;
public Price(MemberStrategy memberStrategy) {
this.memberStrategy = memberStrategy;
}
public void setStrategy(MemberStrategy memberStrategy) {
this.memberStrategy = memberStrategy;
}
public String getType() {
return memberStrategy.getType();
}
public int getPrice() {
return memberStrategy.calculatePrice(100);
}
}
具体调用
public class StrategyPatternDemoMain {
public static void main(String[] args) {
MemberStrategy strategy1 = new NormalMember();
MemberStrategy strategy2 = new MiddleMember();
MemberStrategy strategy3 = new HighMember();
Price price = new Price(strategy1);
System.out.println(price.getType()+" price is:"+price.getPrice());
price.setStrategy(strategy2);
System.out.println(price.getType()+" price is:"+price.getPrice());
price.setStrategy(strategy3);
System.out.println(price.getType()+" price is:"+price.getPrice());
}
}
5. 优缺点
优点
(1)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
(2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。
缺点
(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
(2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
网友评论