Java设计模式之策略模式

前言

策略模式对应于解决某一问题的一个算法族,允许用户从该算法族中任选一个算法解决某一问题,同时可以方便地更换算法或者增加新的算法。策略模式实现了算法定义和算法使用的分离,它通过继承和多态的机制实现对算法族的使用和管理,是一个简单、实用的设计模式。

正文

一、定义

定义如下:

策略模式: 定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法可以独立于使用它的客户而变化。
Strategy Pattern: Define a family of algorithms,encapsulate each one, and make them interchangeable.
Strategy lets the algorithmvary independently from clients that use it.

策略模式又称为政策(Policy)模式,它是一种对象行为型模式。

二、结构

策略模式包含3个角色:
(1)Context(环境类):环境类是使用算法的 角色,它在解决某个问题(即实现某个功能)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。
(2)Strategy(抽象策略类):抽象策略类为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
(3)ConcreteStrategy(具体策略类):具体策略类实现了在抽象策略类中声明的算法,在运行时具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务功能。

三、实现

抽象策略类典型代码如下:

public abstract class AbstractStrategy{
	public abstract void algorithm();	//声明抽象算法
}

具体算法类作为该抽象策略类的子类,代码如下:

public class ConcreteStrategyA extends AbstractStrategy{
	//算法的具体实现
	public void algorithm(){
		//算法A
	}
}

Context类典型代码如下:

public class Context{
	pirvate AbstractStrategy strategy;	//维持一个对抽象策略类的引用

	public void setStrategy(AbstractStrategy strategy){
		this.strategy = strategy;
	}
	
	//调用策略类中的算法
	public void algorithm(){
		strategy.algorithm();
	}

}

客户端代码片段 如下:

...
Context context = new Context();
AbstractStrategy strategy;
strategy = new ConcreteStrategyA();	//可在运行时指定类型,通过配置文件和反射机制实现
context.setStrategy(strategy);
context.algorithm();

策略模式提供了一种可插入式(Pluggable)算法的实现方案。

四、Java SE中的布局管理

Java SE中的容器布局管理是策略模式的一个经典应用实例。
在Java SE开发中,用户需要对容器对象Container中的成员对象(如按钮、文本框等GUI控件)进行布局(Layout),在程序运行期间由客户端动态决定一个Container对象如何布局。JDK提供了几种不同的布局方式,封装在不同的类中。
Container类的代码片段如下:

public class Container extends Component{
	...
	LayoutManager layoutMgr;
	...
	public void setLayout(LayoutManager mgr){
		layoutMgr = mgr;
		...
	}
	...
}

从上述代码可以看出,Container作为环境类,它针对抽象策略类LayoutManager进行编程。根据里氏代换原则,用户在使用时只需要在setLayout()方法中传入一个具体布局对象即可,而无需关心该布局的具体实现。

五、策略模式优缺点与适用环境

优点

(1)策略模式提供了对开闭原则的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
(2)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族,恰当地使用继承可以把公共的代码移到抽象策略类中,从而避免重复的代码。
(3)策略模式提供了一种可以替换继承关系的办法。如果不使用策略模式,那么使用算法的环境类就可能会有一些子类,每一个子类提供一种不同的算法。但是这样一来算法的使用就和算法本身混在一起,不符合单一职责原则,决定使用哪一种算法的逻辑和该算法本身混合在一起,从而不可能再独立演化;而且使用继承无法实现算法或行为再程序运行时的动态切换。
(4)使用策略模式可以避免多重条件选择语句。多重条件选择语句不易维护,它把采取哪一种算法或行为的逻辑与算法或行为本身的实现逻辑混合在一起,将它们全部硬编码在一个庞大的多重条件选择语句中,比直接继承环境类的办法还要原始和落后。
(5)策略模式提供了一种算法的复用机制,由于将算法单独提取出来封装在策略类中,因此不同的环境类可以方便地复用这些策略类。

缺点

(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法。换而言之,策略模式只适用于客户端知道所有算法或行为的情况。
(2)策略模式将造成系统产生很多具体策略类,任何细小的变化都将导致系统要增加一个新的具体策略类。
(3)无法同时在客户端使用多个策略类,也就是说,在使用策略模式时客户端每次只能使用一个策略类,不支持使用一个策略类完成部分功能后再使用另一个策略类完成剩余功能的情况。

适用环境

(1)一个系统需要动态地在几种算法中选择一种,那么可以将这些算法封装到一个个的具体算法类中,而这些具体算法类都是一个抽象算法类的子类。换而言之,这些具体算法类均有统一的接口,根据里氏代换原则和面向对象的多态性,客户端可以选择使用任何一个具体算法类,并只需要维持一个数据类型时抽象算法类的对象。
(2)一个对象有很多行为,使用策略模式把这些行为转移到相应的具体策略类里面,可以避免使用难以维护的多重条件选择语句。
(3)不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法与相关的数据结构,可以提高算法的保密性与安全性。

以上文字,大量摘抄自《Java设计模式》一书,由刘伟老师编著,故本文应当列入转载一类,有兴趣的朋友可以直接阅读原书。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值