当前位置: 首页 > article >正文

从管道符到Java编程

说明:在linux操作系统中,管道符用竖线(|)表示,表示将前一个命令的输出作为后面命令的输入。通过这样“流式”地组合操作,能极大地扩展linux命令功能,处理一些复杂场景。

如下,grep命令,能查看某文件中的关键字,tail命令,能查看文件末尾,通过用管道符连接,能实现查看某关键字,在文件中最后一次出现的位置

在这里插入图片描述

这种设计思想,像流水线一样,从源头到出口,层层处理,最终达到目的,很有启发。在Java的设计模式中,责任链设计模式,就能体现这种思想。

责任链模式介绍,参考下面这篇文章:

  • 【设计模式-4.3】行为型——责任链模式

下面我通过两个在实际工作中的场景,来介绍这种思想的体现

参数校验

一般来说,接口进入Service的第一步是参数校验,如下,

    @Transactional(rollbackFor = Exception.class)
    public List<UserDTO> insert1(UserDTO userDTO) {
        log.info("进入service");
        // 1.参数校验
        userDTO.checkParams();

        // 2.插入数据
        asyncService.insertDTO1(userDTO);

        // 3.返回查询
        return userMapper.selectAll();
    }

UserDTO对象里面,写校验方法,如下:

import cn.hutool.core.util.StrUtil;
import lombok.Data;

import java.io.Serializable;

@Data
public class UserDTO implements Serializable {

    private String id;

    private String username;

    private String password;

    public void checkParams() {
        if (StrUtil.isBlank(username)) {
            throw new IllegalArgumentException("用户名不能为空");
        }

        if (StrUtil.isBlank(password)) {
            throw new IllegalArgumentException("密码不能为空");
        }

        if (username.length() > 25) {
            throw new IllegalArgumentException("用户名长度不能超过25个字符");
        }

        if (!validatePassword(password)) {
            throw new IllegalArgumentException("密码需要包含数字、大小写字符和特殊字符");
        }
    }

    /**
     * 校验密码是否符合要求
     * @param password 密码
     * @return true符合,false不符合
     */
    private boolean validatePassword(String password) {
        // 至少包含一个大写字母
        boolean hasUpperCase = password.matches("(?=.*[A-Z]).*");

        // 至少包含一个小写字母
        boolean hasLowerCase = password.matches("(?=.*[a-z]).*");

        // 至少包含一个数字
        boolean hasDigit = password.matches("(?=.*\\d).*");

        // 至少包含一个特殊字符
        boolean hasSpecialChar = password.matches("(?=.*[!@#$%^&*()\\-_+=\\[\\]{}|;':\",.<>/?]).*");

        return hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar;
    }
}

参考管道符思想,可以设计成如下,将对属性的校验抽出来,解耦,并返回当前对象;

import cn.hutool.core.util.StrUtil;
import lombok.Data;

import java.io.Serializable;

@Data
public class UserDTO implements Serializable {

    private String id;

    private String username;

    private String password;

    public UserDTO checkUsername() {
        if (StrUtil.isBlank(username)) {
            throw new IllegalArgumentException("用户名不能为空");
        }

        if (StrUtil.isBlank(password)) {
            throw new IllegalArgumentException("密码不能为空");
        }
        return this;
    }

    public UserDTO checkPassword() {
        if (username.length() > 25) {
            throw new IllegalArgumentException("用户名长度不能超过25个字符");
        }

        if (!validatePassword(password)) {
            throw new IllegalArgumentException("密码需要包含数字、大小写字符和特殊字符");
        }
        return this;
    }

    /**
     * 校验密码是否符合要求
     * @param password 密码
     * @return true符合,false不符合
     */
    private boolean validatePassword(String password) {
        // 至少包含一个大写字母
        boolean hasUpperCase = password.matches("(?=.*[A-Z]).*");

        // 至少包含一个小写字母
        boolean hasLowerCase = password.matches("(?=.*[a-z]).*");

        // 至少包含一个数字
        boolean hasDigit = password.matches("(?=.*\\d).*");

        // 至少包含一个特殊字符
        boolean hasSpecialChar = password.matches("(?=.*[!@#$%^&*()\\-_+=\\[\\]{}|;':\",.<>/?]).*");

        return hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar;
    }
}

使用的时候,需要校验什么字段就接什么方法

    @Transactional(rollbackFor = Exception.class)
    public List<UserDTO> insert1(UserDTO userDTO) {
        log.info("进入service");
        // 1.参数校验
        userDTO.checkUsername().checkPassword();

        // 2.插入数据
        asyncService.insertDTO1(userDTO);

        // 3.返回查询
        return userMapper.selectAll();
    }

流式组装数据

有个场景,在一个社交系统中,每个用户对象,集成了许多的数据,如

  • 基础信息(头像、昵称、ID、个性签名)
  • 好友数据(好友的基础信息、好友量、权限配置、分组)
  • 系统设置(消息设置、隐私设置、通用)

这些都隶属于一个用户,现在需要获取某个用户的所有信息,通常的做法是分别取查对应的表,然后组装。这里可以使用一种高级的方式,如下:

先写一个接口,定义一个获取用户数据的方法

import org.example.pojo.UserData;

/**
 * 获取用户数据接口
 */
public interface UserDataService {

    /**
     * 获取用户数据
     * @param userData 用户数据
     * @return 用户数据对象
     */
    UserData getUserData(UserData userData);
}

UserData类如下:

import lombok.Data;

import java.io.Serializable;
import java.util.Map;

/**
 * 用户数据
 */
@Data
public class UserData implements Serializable {

    private String id;

    /**
     * 用户数据
     */
    private Map<String, String> data;
}

接着,写三个实现类,分别实现获取基础信息、好友数据、系统设置的方法,如下:

(获取用户基础信息)

import org.example.pojo.UserData;
import org.example.service.UserDataService;
import org.springframework.stereotype.Service;

/**
 * 获取用户基础信息
 */
@Service
public class BaseUserDataService implements UserDataService {

    @Override
    public UserData getUserData(UserData userData) {
        userData.getData().put("基础信息1", "头像");
        userData.getData().put("基础信息2", "昵称");
        userData.getData().put("基础信息3", "ID");
        userData.getData().put("基础信息4", "个性签名");
        return userData;
    }
}

(获取用户好友数据)

import org.example.pojo.UserData;
import org.example.service.UserDataService;
import org.springframework.stereotype.Service;

/**
 * 获取用户好友数据
 */
@Service
public class FriendUserDataService implements UserDataService {

    @Override
    public UserData getUserData(UserData userData) {
        userData.getData().put("好友数据1", "好友的基础信息");
        userData.getData().put("好友数据2", "好友量");
        userData.getData().put("好友数据3", "权限配置");
        userData.getData().put("好友数据4", "分组");
        return userData;
    }
}

(获取用户设置数据)

import org.example.pojo.UserData;
import org.example.service.UserDataService;
import org.springframework.stereotype.Service;

/**
 * 获取用户设置数据
 */
@Service
public class SettingUserDataService implements UserDataService {

    @Override
    public UserData getUserData(UserData userData) {
        userData.getData().put("系统设置1", "消息设置");
        userData.getData().put("系统设置2", "隐私设置");
        userData.getData().put("系统设置3", "通用");
        return userData;
    }
}

使用起来就很方便了,如下:

import org.example.pojo.UserData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;

@Service
public class UserServiceImpl {

    /**
     * 自动装配
     * 把所有 UserDataService 类型的实现类都拿过来
     */
    @Autowired
    private List<UserDataService> userDataServiceList;

    public UserData getUserData() {
        UserData userData = new UserData();
        userData.setId("123456");
        userData.setData(new HashMap<>());
        
        // 调用实现类的方法,去拿对应的数据
        for (UserDataService userDataService : userDataServiceList) {
            userDataService.getUserData(userData);
        }
        return userData;
    }
}

调用接口,查看结果,如下:

在这里插入图片描述

以上方式,利用了Spring自动装配和Java多态(调用接口的方法,实际走的是子类实现的方法)的特性,非常优雅地实现了数据组装。架构搭好,现在只需要针对不同的数据,去实现具体的逻辑即可。个人觉得这种场景在实际业务中应该是比较常见的。

总结

本文从linux管道符的设计思想出发,介绍了这种思想在Java编程上的应用,希望能对大家有启发。


http://www.kler.cn/a/519072.html

相关文章:

  • 使用EasyExcel(FastExcel) 的模板填充报Create workbook failure
  • SQL 指南
  • 蓝桥杯算法赛第25场月赛
  • 计算机网络之应用层
  • Spring WebFlux
  • 页高速缓存与缓冲区缓存的应用差异
  • Linux 常用命令——网络篇(保姆级说明)
  • jira.issueviews
  • 把Eclipse转为AndroidStudio2024.1工程android源码转换过程 解决示例:android蓝牙串口助手
  • C++11线程
  • 超分辨率体积重建实现术前前列腺MRI和大病理切片组织病理学图像的3D配准
  • 【网络编程】Java高并发IO模型深度指南:BIO、NIO、AIO核心解析与实战选型
  • 【技术】TensorRT 10.7 安装指南(Ubuntu22.04)
  • Unity git版本管理
  • react面试题二
  • 人工智能在教育领域的创新应用与前景展望
  • 【内蒙古乡镇界】面图层shp格式+乡镇名称和编码wgs84坐标无偏移arcgis数据内容测评
  • 前端开发中的最新技术——CSS Container Queries: 自适应布局的新纪元
  • 适用于IntelliJ IDEA 2024.1.2部署Tomcat的完整方法,以及笔者踩的坑,避免高血压,保姆级教程
  • CV面试、就业经验分享
  • Linux第一讲--基本的命令操作
  • 【Elasticsearch】权限管理
  • 代理模式 - 代理模式的应用
  • windows11关闭系统更新详细操作步骤
  • 2025数学建模美赛|赛题翻译|E题
  • 使用vitepress搭建自己的博客项目