策略模式:
将可变的部分从程序中抽象分离成算法接口,在该接口下分别封装一系列算法实现。并使他们可以相互替换,从而导致客户端程序独立于算法的改变。
策略模式中的设计原则:变化的抽象成接口;面向接口编程而不是面向实现编程。
为什么要使用策略模式:
在开发程序过程中经常会遇到这种情况,要实现一个功能需要多个不同类型的校验,检测,或者计算规则或者查找和排序,我们最最普通是实现方式是利用if-else来通过各种条件判断出来后再if-else里面写上冗长的代码来实现,造成的结果就是要写很多注释之类来提醒自己那一部分写的是什么内容,代码的阅读特别难,其他人找错的时候代码阅读起来很费劲,这种你方法是硬编码。或者将算法再封装到不同的方法中,这样写也不是很好,维护困难。
使用策略模式使算法和对象分开,使算法可以独立于客户。
适用情况
许多相关的类仅仅是行为有异。 “策略”提供了一种用多个行为中的一个行为来配置一个类的方法。即一个系统需要动态地在几种算法中选择一种。
当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。
一个类定义了多种行为 , 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。
优点
(1) 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
(2) 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族,恰当使用继承可以把公共的代码移到抽象策略类中,从而避免重复的代码。
(3) 策略模式提供了一种可以替换继承关系的办法。如果不使用策略模式,那么使用算法的环境类就可能会有一些子类,每一个子类提供一种不同的算法。但是,这样一来算法的使用就和算法本身混在一起,不符合“单一职责原则”,决定使用哪一种算法的逻辑和该算法本身混合在一起,从而不可能再独立演化;而且使用继承无法实现算法或行为在程序运行时的动态切换。
(4) 使用策略模式可以避免多重条件选择语句。多重条件选择语句不易维护,它把采取哪一种算法或行为的逻辑与算法或行为本身的实现逻辑混合在一起,将它们全部硬编码(Hard Coding)在一个庞大的多重条件选择语句中,比直接继承环境类的办法还要原始和落后。
(5) 策略模式提供了一种算法的复用机制,由于将算法单独提取出来封装在策略类中,因此不同的环境类可以方便地复用这些策略类。
缺点
(1) 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
(2) 策略模式将造成系统产生很多具体策略类,任何细小的变化都将导致系统要增加一个新的具体策略类。
(3) 无法同时在客户端使用多个策略类,也就是说,在使用策略模式时,客户端每次只能使用一个策略类,不支持使用一个策略类完成部分功能后再使用另一个策略类来完成剩余功能的情况。
(4)策略模式将造成产生很多策略类,
组成
环境类(Context):用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用。可定义一个接口来让Strategy访问它的数据。抽象策略类(Strategy):定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy定义的算法。
具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。
下面写个简单的小例子
已女人去健身法每天参加不同课程的锻炼为例
首先:一家健身房需要有很多运动方式,创建一个运动的策略类
/**
* 女人抽象行为接口
* */
public interface WomanStrategy {
/**
* 女人锻炼行为方法
* */
public void operation();
}
第二步:然后是各个不同的策略(不同的运动的实现)
第一个:跑步
/**
* 女人行为实现一:跑步
* */
public class RunStrategy implements WomanStrategy {
/**
* 女人行为实现行为:跑步
* */
@Override
public void operation() {
System.out.println("跑步5公里");
}
}
第二个:拉丁舞
/**
* 女人运动行为实现二:拉丁舞
* */
public class DanceStrategy implements WomanStrategy {
/**
* 女人行为实现行为:拉丁舞
* */
@Override
public void operation() {
System.out.println("拉丁舞课2小时");
}
}
第三个:瑜伽
/**
* 女人运动行为实现三:瑜伽
* */
public class YugaStrategy implements WomanStrategy {
/**
* 女人行为实现行为:瑜伽
* */
@Override
public void operation() {
System.out.println("瑜伽2小时");
}
}
第三步:有一个环境类,可以看做一个健身房,这个健身房有拥有这些运动。
/**
* 女人行为实现的环境:看做一个健身房(调度不同行为,也就是不同运动方式的中心)
* */
public class Context {
private WomanStrategy womanStrategy;//拥有运动
public Context(WomanStrategy womanStrategy) {// 构造函数,决定使用哪个策略(运动)
this.womanStrategy = womanStrategy;
}
public void setWomanStrategy(WomanStrategy womanStrategy) {//将具体策略传给对象
this.womanStrategy = womanStrategy;
}
public void operate(){
this.womanStrategy.operation();//执行被调用的策略(运动)
}
}
第四步:客户,一个女人
/**
* 女人类
* */
public class Woman {
public static void main(String[] args) {
//先到健身房
Context context;
//选课:星期一的课是跑步
context = new Context(new RunStrategy()); //通过构造函数将实现类示例传给环境类。环境类就变成跑步的环境。相当于进入了跑步房
context.operate();//调用跑步的行为,开始跑步
//选课:星期二的课是拉丁舞
context = new Context(new DanceStrategy()); //通过构造函数将实现类示例传给环境类。环境类就变成拉丁舞的环境。相当于进入了拉丁舞练舞厅
context.operate();//调用拉丁舞的行为,开始跳拉丁舞
//选课:星期三的课是瑜伽
context = new Context(new YugaStrategy()); //通过构造函数将实现类示例传给环境类。环境类就变成瑜伽的环境。相当于进入了瑜伽室
context.operate();//调用瑜伽的行为,开始做瑜伽
}
}
以上就是策略模式,多种不同解决方案动态切换,起到改变对象行为的效果。
学习借鉴的其他文章: