设计模式之规约模式

news2025/1/12 6:41:23

设计模式之规约模式

  • 引言
  • 规约模式
    • 案例改造
  • 参考


引言

规约模式的英文是Specification Pattern,Specification直译过来是要求、技术说明、明确的意思。光看名字估计大家都是一脸懵逼,根本不知道这个设计模式大概会是一个什么样子。这也是设计模式的一个通病,就是内涵比较晦涩,很难通过名称来概括。

我们先来简单说说这里规约的意思,它的含义其实很简单,就是把代码当中的代码逻辑以及业务规则区分开。这样的话我们可以在不影响全局的情况下自由地修改和组合这两个部分。

举个例子:

  • 我们都知道QQ里有各种钻石会员,什么绿钻、粉钻之类的。每种会员呢对应一些特殊的权益,假设现在我们新开发了某一个功能,要提供给同时拥有绿钻和粉钻的用户使用。
  • 我们来实现这个逻辑非常简单,只需要一个判断条件就可以了。
    public boolean isSatisfied(User user) {
        return user.isGreenAuth() && user.isPinkAuth();
    }
  • 但是这里有一个问题,这里的逻辑是写死的,时间久了之后,如果这个代码转交给其他人维护了,那么接手的人估计会一脸懵。根本不知道这里为什么要这么判断,也不知道这个函数代表的功能是什么,可能需要去翻很多代码或者是找很多文档才能解决疑惑。
  • 这里的根本问题就是业务规则和实现逻辑混合在一起了,什么意思呢 ?
    • 这里的绿钻 + 粉钻的判断就是业务规则,是为了实现某项功能而制定的,产品经理要的是这个两者叠加的规则。
    • 而我们通过user.isGreenAuth() and user.isPinkAuth()来实现,相当于新建了一个规则,从功能上这当然没有问题。但是问题是这里的规则和代码是定死的。
    • 假设说某一天产品经理提了一个新的需求,不仅需要绿钻 + 粉钻还需要年龄大于18岁,并且年收入超过10w才可以享受这个功能。
    • 那么带来的结果就是我们需要在这个is_satisfied函数当中加上许多代码,随着时间的推移这个函数当中的代码会变得越来越臃肿,并且很有可能以后这当中的一些判断边界需要修改,比如18岁改成20岁,比如10w改成30w等等,这些都是有可能的。当要修改的时候你会发现由于代码的耦合和混乱,改起来非常麻烦。

为了解决这个问题就需要引入规约。


规约模式

规约的意思是把逻辑和规则区分开,规则的归规则,逻辑的归逻辑。

我们还用上面的例子来看,比如在新的需求当中,逻辑本身是很简单的。即粉钻 + 绿钻 + 年龄达标 + 收入达标,这个是规则,而年龄达标和收入达标则是具体的实现。

当我们把规则定好了之后,我们再去解构其中的组件,比如收入达标的定义是年收入大于10w,比如年龄达标的含义是大于18岁。我们可以把这些组件做成单独的模块,这样以后需要修改这些边界的时候,我们只需要在具体实现当中修改就可以了,对于规则的部分就不用动了。同样如果我们需要修改规则,我们也可以避免对实现的改动,这就是规约的意义。

首先,我们需要一个框架用来实现逻辑的组合。

在逻辑当中变量之间的关系只有三种,就是与或非。所以整个逻辑关系还是很清楚的。这里我们采取抽象的方法,先定义接口,再去做具体的实现。这是我们规约出来的条件,它当中有四个接口,分别是与或非的操作接口,以及一个is_satisfied的判断接口。

规约的一个更常用的用途是进行数据筛选,而我们的筛选条件通常是复杂的,因此规约还要实现链式操作。因此需要进行抽象,到达操作一致的目的。

public interface ISpecification<T> {
    boolean isSatisfiedBy(T o);

    ISpecification<T> and(ISpecification<T> specification);

    ISpecification<T> or(ISpecification<T> specification);

    ISpecification<T> not(ISpecification<T> specification);

    default ISpecification<T> and(Function<T, Boolean> function) {
        return and(new CompositeSpecification<T>() {
            @Override
            public boolean isSatisfiedBy(T o) {
                return function.apply(o);
            }
        });
    }

    default ISpecification<T> or(Function<T, Boolean> function) {
        return or(new CompositeSpecification<T>() {
            @Override
            public boolean isSatisfiedBy(T o) {
                return function.apply(o);
            }
        });
    }

    default ISpecification<T> not(Function<T, Boolean> function) {
        return not(new CompositeSpecification<T>() {
            @Override
            public boolean isSatisfiedBy(T o) {
                return function.apply(o);
            }
        });
    }

    public static <T> ISpecification<T> create(Function<T, Boolean> function){
         return new CompositeSpecification<T>() {
             @Override
             public boolean isSatisfiedBy(T o) {
                 return function.apply(o);
             }
         };
    }
}

每个规约实现四个方法:IsSatisfiedBy()、And()、Or()、Not()。IsSatisfiedBy()方法主要实现业务规则,而其它三个则用来将复合业务规则连在一起。

在Specification的基础上,我们进一步实现与或非执行的逻辑:

public abstract class CompositeSpecification<T> implements ISpecification<T>{
    @Override
    public ISpecification<T> and(ISpecification<T> specification) {
        return new AndSpecification<T>(this,specification);
    }

    @Override
    public ISpecification<T> or(ISpecification<T> specification) {
        return new OrSpecification<T>(this,specification);
    }

    @Override
    public ISpecification<T> not(ISpecification<T> specification) {
        return new NotSpecification<T>(specification);
    }
}

对于所有复合规约来说,And()、Or()、Not()方法都是相同的,只有IsSatisfiedBy()方法会有区别。接来下看一下链式规约的实现,分别对应And()、Or()、Not()方法:

public class AndSpecification<T> extends CompositeSpecification<T> {
    private final ISpecification<T> left;
    private final ISpecification<T> right;

    public AndSpecification(ISpecification<T> left, ISpecification<T> right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean isSatisfiedBy(T o) {
        return left.isSatisfiedBy(o) && right.isSatisfiedBy(o);
    }
}
public class OrSpecification<T> extends CompositeSpecification<T> {
    private final ISpecification<T> left;
    private final ISpecification<T> right;

    public OrSpecification(CompositeSpecification<T> left, ISpecification<T> right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean isSatisfiedBy(T o) {
        return left.isSatisfiedBy(o) || right.isSatisfiedBy(o);
    }
}
public class NotSpecification<T> extends CompositeSpecification<T> {
    private final ISpecification<T> specification;

    public NotSpecification(ISpecification<T> specification) {
        this.specification=specification;
    }

    @Override
    public boolean isSatisfiedBy(T o) {
        return !specification.isSatisfiedBy(o);
    }
}

案例改造

用规约模式改造上面给出的案例:

public class SpecificationTest {


    @Test
    public void test(){
        User user = new User(1, 20, 100000, true, false, true);
        //条件: age>18 && inComing>10000 && (greenAuth || pinkAuth)
        ISpecification<User> specification = new UserSpecification().and(u -> u.age > 18).and(u -> u.inComing > 10000)
                .and(ISpecification.create(User::getGreenAuth).or(User::getPinkAuth));
        boolean satisfiedBy = specification.isSatisfiedBy(user);
        System.out.println("是否满足条件: "+satisfiedBy);
    }


    public static class UserSpecification extends CompositeSpecification<User> {

        @Override
        public boolean isSatisfiedBy(User user) {
            return user.enable;
        }
    }

    @Data
    @AllArgsConstructor
    private static class User {
        private Integer id;
        private Integer age;
        private Integer inComing;
        private Boolean greenAuth;
        private Boolean pinkAuth;
        private Boolean enable;
    }
}

在这里插入图片描述


参考

规约模式,颤抖吧产品经理!再也不怕你乱改需求了

规约模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/561174.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

33.Mybatis-Plus

一、Mybatis-Plus。 &#xff08;1&#xff09;简介。 &#xff08;2&#xff09;快速开始_准备工作。 对于Mybatis整合MP有常常有三种用法&#xff0c;分别是MybatisMP、SpringMybatisMP、Spring BootMybatisMP。 &#xff08;2.1&#xff09;创建数据库以及表。 1.创建数…

chatgpt赋能Python-python_lanbda函数

Python Lambda函数&#xff1a;快速、灵活的编程利器 Python是当前最流行的编程语言之一&#xff0c;而在Python中&#xff0c;Lambda函数是一项十分强大的功能&#xff0c;它可以帮助开发者在编写代码时更快地完成任务&#xff0c;提高代码的灵活性和可读性。本文将介绍Pytho…

【Linux】Linux小程序(进度条)、git命令行的使用及gdb的使用

&#x1f601;作者&#xff1a;日出等日落 &#x1f514;专栏&#xff1a;Linux 辛勤的蜜蜂永没有时间悲哀。 ——布莱克 目录 \r和\n的区别&#xff1a; 进度条小程序 git 命令行 Linux调试器&#xff1a;…

Linux-模拟一个简单的shell

什么是shell外壳&#xff1f;就是操作系统给我们的一个命令行解释器&#xff0c;在Linux系统中&#xff0c;它的shell叫做bash。 那么bash本质是什么呢&#xff1f; 本质就是一个文件&#xff0c;一个进程。 万物皆文件 每个操作系统的shell都是很复杂的&#xff0c;想要…

chatgpt赋能Python-python_o_n_

Python O(n)的介绍 Python是世界上最流行的编程语言之一&#xff0c;因为其简单易学的语法&#xff0c;强大的功能和广泛的使用领域。对于程序员来说&#xff0c;时间复杂度是非常重要的一个概念。它用来描述一个算法在处理输入数据时所需的时间和空间资源。 在计算机科学的算…

CSS中块级元素,行内块元素,行内元素的特点

CSS自学笔记 目录 一、什么是元素显示模式 二、CSS的元素显示模式 1.块元素 2.行内元素 3.行内块元素 前言 网页的标签非常多&#xff0c;在不同地方会用到不同类型的标签&#xff0c;了解他们的特点可以更好的布局我们的网页。 HTML 元素一般分为块元素和行内元素两种类型…

220v转15v芯片-220v转15v用什么芯片?

FET开关&#xff0c;具有高效率和稳定性。 Q&#xff1a;为什么需要将220v转换为15v&#xff1f; A&#xff1a;在家庭电器和电子设备中&#xff0c;很多电路需要低电压直流电源供电。而家庭供电一般为220v交流电&#xff0c;需要经过转换才能得到所需的低电压直流电源。 Q&…

错题记录—哪个类用到了解决哈希冲突的开放定址法,MYSQL实现主从复制的日志是哪种,Java对象的初始化方式有

解决哈希冲突&#xff08;四种方法&#xff09;&#xff1a; 1、开放定址法&#xff1a;我们在遇到哈希冲突时&#xff0c;去寻找一个新的空闲的哈希地址。 &#xff08;1&#xff09;线性探测法 &#xff08;2&#xff09;平方探测法&#xff08;二次探测&#xff09; 2、再哈…

题解2023.5.23(欧拉筛)

C.Hossamand Trainees 欧拉筛,预处理先筛出质数&#xff0c;分解质因数对于出现两次及以上的输出yes 我们需要筛出根号(1e9)以内的所有质数&#xff0c;根据质数定理&#xff0c;大约有4e^3个质数&#xff0c; 时间复杂度分析&#xff1a;le5*4e34e8 #include<bits/stdc.…

Python 3.10.11 liunx系统安装

官网下载 https://www.python.org/downloads/source/ 将tar包上传服务器安装 安装基础功能软件 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel 解压安装 tar -z…

chatgpt赋能Python-python_noob

Python for Beginners: An Introduction to the World’s Most Popular Programming Language Python is a high-level programming language that has become one of the most popular and widely used languages in the world. It’s simple, easy to read, and has a vast …

chatgpt赋能Python-python_pecan

Python Pecan: 构建Web应用程序的高效框架 Python是一种简单易学、功能强大的编程语言&#xff0c;非常适合Web应用程序的开发。而Pecan则是一个基于Python的高效框架&#xff0c;可以简化Web应用程序的开发过程。本文将介绍Python Pecan框架的优点、使用方法和性能表现。 什…

计算机网络考试多选题汇总Ⅱ(请关注博客在资源文档下载完整答案)

https://cadyin.blog.csdn.nethttps://blog.csdn.net/qq_38639612?spm1010.2135.3001.5421 计算机网络考试多选题汇总 1、在Windows中&#xff0c;任务管理器的作用是() A&#xff0e;终止未响应的应用程序 B&#xff0e;终止进程的运行 C&#xff0e;查看系统当前的信息 …

【新星计划·2023】网络协议———DHCP讲解

前言 在工作中&#xff0c;利用DHCP可以有效的节约IP地址&#xff0c;既保证了网络通信&#xff0c;又提高IP地址的使用率。 一、DHCP是什么&#xff1f; DHCP全称为Dynamic Host Configuration Protocol&#xff0c;是一种网络管理协议&#xff0c;中文含义为“动态主机配置…

node版本引起的一系列问题

1. 安装node node官方地址 下载对应系统zip到对应的文件夹解压 在目录下创建文件夹node_cache 和 node_global 修改 npm 配置&#xff0c;配置 npm 的全局模块的存放路径以及 cache 的路径 //npm config set prefix 文件路径 npm config set prefix D:\software\nodeJs\n…

shell 免交互

文章目录 Here Document 免交互实验多行注释基本命令 实验 Here Document 免交互 使用I/O重定向的方式将命令列表提供给交互式程序或命令&#xff0c;比如 ftp、cat 或 read 命令。是标准输入的一种替代品可以帮助脚本开发人员不必使用临时文件来构建输入信息&#xff0c;而是…

DR2: Diffusion-based Robust Degradation Remover for Blind Face Restoration

DR2: Diffusion-based Robust Degradation Remover for Blind Face Restoration (Paper reading) Zhixin Wang, Shanghai Jiao Tong University, CH, CVPR2023, Cited:0, Code, Paper 1. 前言 传统的盲脸部修复通常使用预定义的退化模型来合成降质的低质量数据进行训练&#…

CodeForces.1810B.糖果.[中等][ifelse选择][注意输出格式]

题目描述&#xff1a; 解题思路&#xff1a; 题目解读&#xff1a; 初始状态只有一个糖果&#xff0c;即x1&#xff0c;给定想要获得的总糖果数y。 只能进行两种操作&#xff0c;分别是做2x-1和2x1。给出从 x1 到 目标数字 y 的操作步数和具体步骤。 示例1 从1到2&#xff…

2023最全CTF入门指南(建议收藏)

目录 一、CTF简介 二、CTF竞赛模式 三、CTF各大题型简介 四、CTF学习路线 4.1、初期 1、htmlcssjs&#xff08;2-3天&#xff09; 2、apachephp &#xff08;4-5天&#xff09; 3、mysql &#xff08;2-3天&#xff09; 4、python (2-3天) 5、burpsuite &#xff08;…

防火墙——iptables防火墙(四表五链、防火墙配置方法、匹配规则详解)

iptables防火墙 一、Linux包过滤防火墙1、Linux防火墙概述2、netfilter3、iptables4、netfilter/iptables关系 二、四表五链1、表链作用2、四表3、五链4、数据包到达防火墙时&#xff0c;规则表之间的优先顺序5、规则链之间的匹配顺序 三、iptables的安装四、iptables防火墙的配…