策略模式
在软件开发中常常会遇到,要实现一个功能(例如排序、查找)有很多种算法,一种常用的方法是通过硬编码将所有的算法集中在一个类中,在该类中提供多个方法,每一个方法对应一个具体的算法;当然也可以将这些算法封装在一个统一的方法中,通过if-else等条件判断语句进行选择。这两种实现方法都可以称为硬编码,如果需要增加一种新的算法,需要修改算法类的源代码;更换算法也需要修改客户端调用代码,在这个统一的算法类中封装了大量算法,代码非常复杂,维护也很困难。
此时可以使用一种设计模式来实现灵活地选择算法,还能够方便地增加新的算法,该设计模式就是策略模式。在策略模式中可以定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法,在这里的每一个封装算法的类都可以称为一种策略,为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做算法的声明,而每种算法对应一个具体策略类。
策略模式结构:
1.Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个功能)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义锁采用的策略。
2.Strategy(抽象策略类):抽象策略类为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或者具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行调用具体策略类中实现的算法。
3.ConcreteStrategy(具体策略类):具体策略类实现了在抽象策略类中声明的算法,在运行时具体策略类将覆盖环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务功能。
策略模式的实例:
策略模式是一个很容易理解和使用的设计模式,策略模式是对算法的封装,它吧算法的责任和算法本身分隔开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列具体策略类里面,作为抽象策略类的子类。在策略模式中对环境类和抽象策略类的理解非常重要,环境类是需要使用算法的类。在一个系统中可以存在多个环境类,它们可能需要重用一些相同的算法。
在使用策略模式时需要将算法从环境类Context中提取出来,首先应该创建一个抽象策略类,其典型代码如下:
public abstract class AbstractStrategy{
public abstract void algorithm(); //声明抽象算法
}
然后封装每一种具体算法的类作为该抽象策略类的子类,其实现代码如下:
public class ConcreteStrategyA extends AbstractStrategy{
//算法的具体实现
public void algorithm(){
//算法A
}
}
对于环境类而言,在他与抽象策略类之间建立一个关联关系,其典型代码如下
public class Context{
private AbstractStrategy strategy; //维持一个对抽象策略类的引用
public void setStrategy(AbstractStrategy strategy){
this.strategy=strategy;
}
//调用策略类中的算法
public void algorithm(){
strategy.algorithm();
}
}
在环境类中定义一个抽象策略类型的对象strategy,通过注入的方式在客户端传入一个具体策略类对象,客户端代码如下:
public class Client{
public static void main(String args[]){
Context context = new context();
AbstractStrategy strategy;
strategy = new ConcreteStrategy(); //运行时指定类型
context.setStrategy(strategy); //注入具体策略类
context.algorithm(); //调用具体策略类的方法
}
}
在客户端代码中只需填注入一个具体策略类对象,可以将具体策略类的类名存储在配置文件中,通过反射来动态创建具体策略对象,从而使得用户可以灵活地更换具体策略类,增加新的具体策略类也很方便。策略模式提供了一种可插入是算法的实现方案。
本文借鉴了刘伟老师的《Java设计模式》一书以及老师的相关博客