设计模式--策略模式和责任链模式

策略模式

策略模式(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();
    }
}

策略模式的优缺点:

优点:

  1. 策略模式符合开闭原则
  2. 避免使用多重条件转移语句,如if..else...语句、switch语句
  3. 使用策略模式可以提高算法的保密性和安全性

缺点

  1. 客户端必须知道所有的策略,并且自行决定使用哪个策略类
  2. 代码中会产生非常多策略类,增加维护难度。

责任链模式

责任链模式(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));
    }

}

责任链模式的优缺点:

优点:

  • 将请求与处理解耦
  • 请求处理者只需关注自己感兴趣的请求进行处理,对于不感兴趣的请求,直接转发给下一级节点对象。
  • 具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果;
  • 链路结构灵活,可以通过改变链路结构动态地新增或删除责任
  • 易于扩展新的请求处理类,符合开闭原则

缺点:

  • 责任链太长或者处理时间过长,会影响整体性能
  • 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。
相关推荐
吾日三省吾码3 小时前
JVM 性能调优
java
弗拉唐4 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi775 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
少说多做3435 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀5 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20206 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深6 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
shuangrenlong6 小时前
slice介绍slice查看器
java·ubuntu
牧竹子6 小时前
对原jar包解压后修改原class文件后重新打包为jar
java·jar