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

news/2024/5/19 14:24:40 标签: 设计模式, 策略模式, 责任链模式, java

策略模式

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

}

责任链模式的优缺点:

优点:

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

缺点:

  • 责任链太长或者处理时间过长,会影响整体性能
  • 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。

http://www.niftyadmin.cn/n/5394095.html

相关文章

Elasticsearch 别名(Aliases)的作用

Elasticsearch 8.4.3 别名&#xff08;Aliases&#xff09; 一. 介绍二. 别名的优势三. 别名的基本操作3.1 创建别名3.2 查询别名关联的索引3.3 删除别名3.4 更新别名3.5 通过别名查询数据 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接…

第七章回溯_组合

吾日三省吾身 还记得的梦想吗 正在努力实现它吗 可以坚持下去吗 力扣题号&#xff1a;77. 组合 - 力扣&#xff08;LeetCode&#xff09; 下述题目描述和示例均来自力扣 题目描述 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何…

FMM 笔记:FMM(colab上执行)【官方案例解读】

在colab上运行&#xff0c;所以如何在colab上安装fmm&#xff0c;可见FMM 笔记&#xff1a;在colab上执行FMM-CSDN博客 fmm见&#xff1a;论文笔记&#xff1a;Fast map matching, an algorithm integrating hidden Markov model with precomputation_ubodt(upper bounded ori…

Elasticsearch 创建index库 timeout

问题概述 使用 python 客户端 代码进行创建,【之前成功创建,但是现在出现报错,报错代码es_connection.client.indices.create】def create_vector_index(dataset_index_name,vector_query_field,query_field):es_connection = get_collention(dataset_index_name,vector_que…

掌握「4组」关键数字:14064-1、14064-2、14064-3、14067,助你在可持续道路上快速成功!

随着可持续发展在企业界迅速吹拂&#xff0c;温室气体盘查法规使得每个企业都必须直视盘查的挑战。是的&#xff0c;进入温室气体管理的世界初期&#xff0c;你可能会被一长串的专业英文字母和数字组合搅得头昏脑胀&#xff1a;GHG、scope、碳汇、碳抵销、碳市场、碳权、ESG、1…

ad如何生成gerber文件

1 2 3 4 5 6 7 8![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/f576afa92b054a5ca68bc383a4c3c27d.png#pic_ce 8 9 10

Java项目:21 基于SSM实现的图书借阅管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 基于SSM实现的图书借阅管理系统设计了两个角色&#xff0c;分别是管理员、用户&#xff0c;在数据表user中以ident字段区分&#xff0c;为1表示…

【Docker】03 容器操作

文章目录 一、流转图二、基本操作2.1 查看本地容器进程2.2 启动容器2.2.1 交互式启动容器2.2.2 后台启动容器 2.3 进入容器2.4 停止启动重启容器2.5 退出容器2.6 删除容器2.7 提交容器&#xff08;打包成镜像&#xff09;2.8 拷贝文件2.8.1 拷贝容器内文件到宿主机2.8.2 拷贝宿…