策略模式 是指有一定行动内容的相对稳定的策略名称。用比较易懂的话来说就是,定义算法族,分别封装起来,让它们之间可以互相替换。
(一)简介
1. 主要解决的问题
在一个系统中,如果某个问题有多种解决方案(即有多种相似算法的情况下),如果使用if...else...
去控制这些算法的使用,会使得代码变得冗长及复杂化,因此,会使得系统变的更复杂和难以维护。
如果将这些算法封装成一个个的类,并且实现同一个接口,那么这些算法可以任意地被替换。
当系统在运行时,如果想改变某种行为或解决方法的话,只需要setter
相关的算法类即可,不用再通过if...else...
的判断逻辑去决定使用哪个算法。这样就可以使得代码行数变得更少,代码逻辑更清晰,使得代码更具有可读性。
2. 优缺点
-
优点:
- 算法可以自由切换;
- 避免使用多重条件判断;
- 扩展性良好。
-
缺点:
- 策略类会增多;
- 所有策略类都需要对外暴露。
3. 使用场景
使用策略模式时,主要考虑以下几个场景:
- 如果系统中有许多类,而这些类之间的区别仅在于它们的算法不同,那么使用策略模式可以动态地让对象在多种算法中选择一种;
- 如果系统需要动态地在几种算法中选择一种,那么使用策略模式可以更方便;
- 如果对象的某种行为中,有多重条件选择语句,最好是选择策略模式。
(二)实现
为了更好的解释策略模式,我们举一个日常生活中常见的例子来说明。
1. 需求说明
某视频网站正在播出一部热门电视剧,但是,神坑的是,该视频网站采取饥饿营销的方式,每周只更新几集。
为了更好的服务广大消费者(其实,是为了掏空看客老爷们口袋中的钱),该网站推出了“充会员,比别人更早拥有”的活动。
网站规定:普通用户每周只能看四集;VIP
用户每周可以看六集;SVIP
用户每周可以看八集。
那么,请你设计一个权限控制系统,以此来控制不同权限用户的观看集数。
2. 系统设计
根据上述的需求说明,我们可以得出结论: 每位用户都可以看视频,唯一不同的是看的集数不一样。
基于该结论,我们可以认为:每个对象(用户)的活动(看视频)都是一样的,不同的是行为(看的集数)不同。那么,我们采用策略模式,来设计这套权限控制系统。
通过上述分析,我们构建一个Permission
接口;三个不同的权限用户,分别是NormalPermission
、VipPermission
、SvipPermission
,它们都实现了Permission
接口;另外,我们还需要一个使用了上述三种策略的类,暂且叫它WatchVideo
。
类图如下:
3. 代码实现
(1)构建Permission
接口
/**
*
* 权限接口
* @author Levi
* @date 2021/7/24
*/
public interface Permission {
/**
* 校验权限,返回可看剧集的集数
* @return
*/
int checkPermission();
}
(2)构建三个不同权限的用户
1. 普通用户权限,只可以看四集
/**
*
* 普通用户权限
* @author Levi
* @date 2021/7/24
*/
public class NormalPermission implements Permission{
/**
* 普通用户可以看四集
* @return
*/
@Override
public int checkPermission() {
System.out.println("普通用户,每周只可以看四集。");
return 4;
}
}
2. VIP用户权限,可以看六集
/**
*
* VIP用户权限
* @author Levi
* @date 2021/7/24
*/
public class VipPermission implements Permission{
/**
* VIP用户可以看六集
* @return
*/
@Override
public int checkPermission() {
System.out.println("VIP用户,每周只可以看六集。");
return 6;
}
}
3. SVIP用户权限,可以看八集
/**
*
* SVIP用户权限
* @author Levi
* @date 2021/7/24
*/
public class SvipPermission implements Permission{
/**
* VIP用户可以看八集
* @return
*/
@Override
public int checkPermission() {
System.out.println("SVIP用户,每周只可以看八集。");
return 8;
}
}
(3)构建使用类
在使用类中,通过构造器动态实例化permission
接口,以此达到通过一个方法调用多种算法的目的。
/**
*
* 看剧的行为
* @author Levi
* @date 2021/7/24
*/
public class WatchVideo {
//permission接口
private Permission permission;
/**
* 在WatchVideo的构造器中,动态实例化permission
* @param permission
*/
public WatchVideo(Permission permission) {
this.permission = permission;
}
/**
* 校验用户权限,返回可以看的集数
* @return
*/
public int excutePermission() {
return permission.checkPermission();
}
}
(4)测试
使用watchVideo
来查看当它改变策略permission
时的结果变化。
/**
*
* 测试策略模式
* @author Levi
* @date 2021/7/24
*/
public class TestStrategy {
public static void main(String[] args) {
WatchVideo watchVideo;
//不同权限用户
// watchVideo=new WatchVideo(new NormalPermission());
watchVideo=new WatchVideo(new VipPermission());
// watchVideo=new WatchVideo(new SvipPermission());
int result=watchVideo.excutePermission();
System.out.println(result);
}
}
打印结果: