Java设计模式-策略模式

策略模式介绍

策略模式在23种设计模式中归类为对象行为模式。在平常开发过程中也是比较常见的一种设计模式

策略模式的主要意图是针对一系列算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

策略模式一般设计到三个角色:

  • 环境(Context)角色:持有一个Strategy的引用。
  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

环境(Context)角色类。

public class Context {
	
	private Strategy strategy;

	public Context(Strategy strategy) {
		this.strategy = strategy;
	}
	
	public void contextMethod(){
		//...
		this.strategy.strategyMethod();
		//...
	}
}

抽象策略(Strategy)角色类,在一般开发中策略方法应该具有某种特定的返回类型,这样可以在算法执行之后得到所需要的返回值。

public interface Strategy {
	
	void strategyMethod();

}

具体策略(ConcreteStrategy)角色类。

public class ConcreteStrategyA implements Strategy{

	@Override
	public void strategyMethod() {
		System.out.println("ConcreteStrategyA Method");
	}

}

策略模式的应用场景

  • 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
  • 一个系统需要动态地在几种算法中选择一种。
  • 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
  • 不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。

策略模式应用举例

简单示例

假设在设计一个在线电子商务系统,这里有普通会员和黄金会员,普通会员可以打九折,而黄金会员是七五折。这里只是一种很简单的设计,在真正的电子商务软件开发中可能遇到的会员种类更多。根据描述,将会员可以打折的策略设计成策略模式,这样在日后可以新增更多更细的打折优惠措施。

首先定义一个会员折扣的抽象类。

public interface MemberStrategy {

	double calcPrice(double goodsPrice);
	
}

然后实现两种会员策略。

//普通会员
public class CardMemberStrategy implements MemberStrategy{

	@Override
	public double calcPrice(double goodsPrice) {
		return goodsPrice*0.9;
	}

}
//黄金会员
public class GoldMemberStrategy implements MemberStrategy{

	@Override
	public double calcPrice(double goodsPrice) {
		return goodsPrice*0.75;
	}

}

最后定义一个价格类。

public class Price {
	
	private MemberStrategy strategy;

	public Price(MemberStrategy strategy) {
		this.strategy = strategy;
	}
	
	public double quote(double goodsPrice){
        return this.strategy.calcPrice(goodsPrice);
    }

}

客户端测试类。

public class MainTest {
	
	public static void main(String[] args) {
		MemberStrategy strategy=new GoldMemberStrategy();
		Price price=new Price(strategy);
		System.out.println("折扣后商品价格:"+price.quote(10));//7.5
	}
}

从示例中可以看出,策略模式仅仅是封装算法,用于扩展提供新的算法插入到已有系统中。实际上它并不决定在何时使用何种算法,在什么情况下使用某种算法是由客户端决定的。

Java中策略模式的应用

Comparator比较器

Java中位于java.util包下的Comparator就是使用的策略模式。实现Comparator接口的类必然就会实现一个compareTo(Object o1, Object o2)的方法,而这个方法就是算法中的一部分,所有使用了compareTo方法的类都不会关心compareTo是如何工作的,只关心它的返回值,这也是面向对象中著名的封装特性。

RecyclerView中LayoutManager

在Android开发的support中的RecyclerView提供了一个布局管理器LayoutManager,该LayoutManager扮演的就是抽象策略角色。针对不同的示例图类型提供了线性布局管理器LinearLayoutManager、网格布局管理器GridLayoutManager 以及瀑布流布局管理器StaggeredGridLayoutManager。

策略模式特征

策略模式的重心策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。

算法的平等性策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。

运行时策略的唯一性运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。

公有的行为经常见到的是,所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。当然这时候抽象策略角色必须要用Java抽象类实现,而不能使用接口。

策略模式优缺点

策略模式优点

策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。

策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。

使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。

策略模式缺点

客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。

由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。

参考资料

《JAVA与模式》之策略模式

策略模式

Java与设计模式

GOF设计模式

Java设计模式

评论

您确定要删除吗?删除之后不可恢复