策略模式
策略模式(Strategy Pattern)又叫做政策模式,它是将定义的算法家族、分别包装起来,让它们之间可以相互替换,从而让算法的变化不会影响到使用算法的用户。属于行为型模式。
策略模式使用的就是面向对象的继承和多态机制,从而实现同一行为在不同场景下具备不同实现。
应用场景:
- 针对同一类型问题,有多种处理方式,每一种都能独立解决问题;
- 算法需要自由切换的场景;
- 需要屏蔽算法规则的场景;
java
/**
* 促销策略抽象
*/
interface IPromotionStrategy{
void doPromotion();
}
class CouponbuyStrategy implements IPromotionStrategy{
@Override
public void doPromotion() {
System.out.println("使用优惠卷抵扣");
}
}
class CashbackStrategy implements IPromotionStrategy{
@Override
public void doPromotion() {
System.out.println("返现");
}
}
class EmptyStrategy implements IPromotionStrategy{
@Override
public void doPromotion() {
System.out.println("无优惠");
}
}
class PromotionActivity{
private IPromotionStrategy strategy;
public PromotionActivity(IPromotionStrategy strategy) {
this.strategy = strategy;
}
public void excute(){
strategy.doPromotion();
}
}
public class Test {
public static void main(String[] args) {
PromotionActivity activity618 = new PromotionActivity(new CouponbuyStrategy());
PromotionActivity activity1111 = new PromotionActivity(new CashbackStrategy());
activity618.excute();
activity1111.excute();
}
}
//public class Test {
// public static void main(String[] args) {
// PromotionActivity activity = null;
//
// String promotionKey = "COUPON";
//
// if(promotionKey.equals("COUPON")){
// activity = new PromotionActivity(new CouponbuyStrategy());
// }else if(promotionKey.equals("CASHBACK")){
// activity = new PromotionActivity(new CashbackStrategy());
// }
//
// activity.excute();
// }
//}
我们可以结合单例模式和工厂模式优化上述代码:
java
class PromotionStrategyFactory{
private static Map<String,IPromotionStrategy> PROMOTIONS = new HashMap<>();
private interface PromotionKey{
String COUPON = "COUPON";
String CASHBACK = "CASHBACK";
}
static {
PROMOTIONS.put(PromotionKey.COUPON,new CouponbuyStrategy());
PROMOTIONS.put(PromotionKey.CASHBACK,new CashbackStrategy());
}
private static final IPromotionStrategy EMPTY = new EmptyStrategy();
private PromotionStrategyFactory(){}
public static IPromotionStrategy getPromotionStrategy(String promotionKey){
IPromotionStrategy strategy = PROMOTIONS.get(promotionKey);
return strategy==null?EMPTY:strategy;
}
public static Set<String> getPromotionKeys(){
return PROMOTIONS.keySet();
}
}
public class Test {
public static void main(String[] args) {
String promotionKey = "COUPON";
IPromotionStrategy promotionStrategy = PromotionStrategyFactory.getPromotionStrategy(promotionKey);
promotionStrategy.doPromotion();
}
}
策略模式的优缺点:
优点:
- 策略模式符合开闭原则
- 避免使用多重条件转移语句,如if..else...语句、switch语句
- 使用策略模式可以提高算法的保密性和安全性
缺点
- 客户端必须知道所有的策略,并且自行决定使用哪个策略类
- 代码中会产生非常多策略类,增加维护难度。
责任链模式
责任链模式(Chain of Responsibility Pattern)是将链中每一个节点看作是一个对象,每个节点处理的请求不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端出发时,会沿着链的路径依次传递给每一个对象,直至有对象处理这个请求为止。属于行为模式。
责任链模式主要是解耦了请求与处理,客户只需要将请求发送到链上即可,无需关心请求的具体内容和处理细节,请求会自动进行传递直至有节点对象进行处理。适用于以下应用场景:
- 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定;
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;
- 可动态指定一组对象处理请求。
利用责任链模式进行数据校验拦截:
java
import lombok.Data;
import org.junit.platform.commons.util.StringUtils;
@Data
class Member{
private String loginName;
private String loginPass;
private String roleName;
public Member(String loginName, String loginPass) {
this.loginName = loginName;
this.loginPass = loginPass;
}
}
/**
* 臃肿的代码
*/
class MemberService{
public void login(String loginName,String loginPass){
if(StringUtils.isBlank(loginName) || StringUtils.isBlank(loginPass)){
System.out.println("登录信息不能为空");
}
Member member = checkExists(loginName,loginPass);
if(member == null){
System.out.println("用户不存在");
}
if(!"管理员" .equals(member.getRoleName())){
System.out.println("用户权限不够");
}
System.out.println("登录成功");
}
private Member checkExists(String loginName, String loginPass){
Member member = new Member(loginName,loginPass);
member.setRoleName("管理员");
return member;
}
}
/**
* 利用责任链优化代码
*/
abstract class Handler{
protected Handler chain;
public void next(Handler handler){
this.chain = handler;
}
public abstract void doHandle(Member member);
}
/**
* 为空校验
*/
class ValidateHandler extends Handler{
@Override
public void doHandle(Member member) {
if(StringUtils.isBlank(member.getLoginName()) || StringUtils.isBlank(member.getLoginPass())){
System.out.println("登录信息不能为空");
return;
}
chain.doHandle(member);
}
}
class LoginHandler extends Handler{
@Override
public void doHandle(Member member) {
/**
* 查询用户是否存在
*/
System.out.println("登录成功");
member.setRoleName("管理员");
chain.doHandle(member);
}
}
/**
* 权限验证
*/
class AuthHandler extends Handler{
@Override
public void doHandle(Member member) {
if(!"管理员".equals(member.getRoleName())){
System.out.println("权限不够");
return;
}
System.out.println("登录成功");
}
}
class MemberService2{
public void login(String loginName,String loginPass){
ValidateHandler validateHandler = new ValidateHandler();
LoginHandler loginHandler = new LoginHandler();
AuthHandler authHandler = new AuthHandler();
validateHandler.next(loginHandler);
loginHandler.next(authHandler);
validateHandler.doHandle(new Member(loginName,loginPass));
}
}
public class Test {
public static void main(String[] args) {
MemberService memberService = new MemberService();
memberService.login("tom","666");
MemberService2 memberService2 = new MemberService2();
memberService2.login("tom","666");
}
}
另外,链式的组装过于复杂,可以建造者模式处理节点对象进行自动链式组装。处理节点对象顺序不同,构造出来的链式结构也随之不同。修改后的代码:
java
/**
* 利用责任链优化代码
*/
abstract class Handler{
protected Handler chain;
public void next(Handler handler){
this.chain = handler;
}
public abstract void doHandle(Member member);
public static class Builder{
private Handler head;
private Handler tail;
public Builder addHandler(Handler handler){
if(this.head == null){
this.head = this.tail = handler;
return this;
}
this.tail.next(handler);
this.tail=handler;
return this;
}
public Handler build(){
return this.head;
}
}
}
class MemberService2{
public void login(String loginName,String loginPass){
// ValidateHandler validateHandler = new ValidateHandler();
// LoginHandler loginHandler = new LoginHandler();
// AuthHandler authHandler = new AuthHandler();
//
// validateHandler.next(loginHandler);
// loginHandler.next(authHandler);
//
// validateHandler.doHandle(new Member(loginName,loginPass));
Handler.Builder builder = new Handler.Builder();
builder.addHandler(new ValidateHandler())
.addHandler(new LoginHandler())
.addHandler(new AuthHandler());
builder.build().doHandle(new Member(loginName,loginPass));
}
}
责任链模式的优缺点:
优点:
- 将请求与处理解耦
- 请求处理者只需关注自己感兴趣的请求进行处理,对于不感兴趣的请求,直接转发给下一级节点对象。
- 具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果;
- 链路结构灵活,可以通过改变链路结构动态地新增或删除责任
- 易于扩展新的请求处理类,符合开闭原则
缺点:
- 责任链太长或者处理时间过长,会影响整体性能
- 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。