《Java工程师必读手册》——Java极客主义系列——Java代码精简之道(9)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 《Java工程师必读手册》——Java极客主义系列——Java代码精简之道(9)

接上篇:https://developer.aliyun.com/article/1227318?spm=a2c6h.13148508.setting.20.48e04f0eaBVGWH


十、 利用设计模式

 

1. 模板方法模式

 

模板方法模式(Template Method Pattern)定义一个固定的算法框架,而将算法的一些步骤放到子类中实现,使得子类可以在不改变算法框架的情况下重定义该算法的某些步骤。

 

普通

 

@Repository

public class UserValue {

    /** 值操作 */

    @Resource(name = "stringRedisTemplate")

    private ValueOperations<String, String> valueOperations;

    /** 值模式 */

    private static final String KEY_FORMAT = "Value:User:%s";

 

    /** 设置值 */

    public void set(Long id, UserDO value) {

        String key = String.format(KEY_FORMAT, id);

        valueOperations.set(key, JSON.toJSONString(value));

    }

 

    /** 获取值 */

    public UserDO get(Long id) {

        String key = String.format(KEY_FORMAT, id);

        String value = valueOperations.get(key);

        return JSON.parseObject(value, UserDO.class);

    }

 

    ...

}

 

@Repository

public class RoleValue {

    /** 值操作 */

    @Resource(name = "stringRedisTemplate")

    private ValueOperations<String, String> valueOperations;

    /** 值模式 */

    private static final String KEY_FORMAT = "Value:Role:%s";

 

    /** 设置值 */

    public void set(Long id, RoleDO value) {

        String key = String.format(KEY_FORMAT, id);

        valueOperations.set(key, JSON.toJSONString(value));

    }

 

    /** 获取值 */

    public RoleDO get(Long id) {

        String key = String.format(KEY_FORMAT, id);

        String value = valueOperations.get(key);

        return JSON.parseObject(value, RoleDO.class);

    }

 

    ...

}

 

精简

 

public abstract class AbstractDynamicValue<I, V> {

    /** 值操作 */

    @Resource(name = "stringRedisTemplate")

    private ValueOperations<String, String> valueOperations;

 

    /** 设置值 */

    public void set(I id, V value) {

        valueOperations.set(getKey(id), JSON.toJSONString(value));

    }

 

    /** 获取值 */

    public V get(I id) {

        return JSON.parseObject(valueOperations.get(getKey(id)), getValueClass());

    }

 

    ...

 

    /** 获取主键 */

    protected abstract String getKey(I id);

 

    /** 获取值类 */

    protected abstract Class<V> getValueClass();

}

 

@Repository

public class UserValue extends AbstractValue<Long, UserDO> {

    /** 获取主键 */

    @Override

    protected String getKey(Long id) {

        return String.format("Value:User:%s", id);

    }

 

    /** 获取值类 */

    @Override

    protected Class<UserDO> getValueClass() {

        return UserDO.class;

    }

}

 

@Repository

public class RoleValue extends AbstractValue<Long, RoleDO> {

    /** 获取主键 */

    @Override

    protected String getKey(Long id) {

        return String.format("Value:Role:%s", id);

    }

 

    /** 获取值类 */

    @Override

    protected Class<RoleDO> getValueClass() {

        return RoleDO.class;

    }

}

 

 

 

2. 访问者模式

 

访问者模式(Visitor),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

 

普通

 

public interface DataHandler<T> {

    /** 解析数据 */

public T parseData(Record record);

    

    /** 存储数据 */

public boolean storeData(List<T> dataList);

}

 

public <T> long executeFetch(String tableName, int batchSize, DataHandler<T> dataHandler) throws Exception {

    // 构建下载会话

    DownloadSession session = buildSession(tableName);

 

    // 获取数据数量

    long recordCount = session.getRecordCount();

    if (recordCount == 0) {

        return 0;

    }

 

    // 进行数据读取

    long fetchCount = 0L;

    try (RecordReader reader = session.openRecordReader(0L, recordCount, true)) {

        // 依次读取数据

        Record record;

        List<T> dataList = new ArrayList<>(batchSize);

        while ((record = reader.read()) != null) {

            // 解析添加数据

            T data = dataHandler.parseData(record);

            if (Objects.nonNull(data)) {

                dataList.add(data);

            }

 

            // 批量存储数据

            if (dataList.size() == batchSize) {

                boolean isContinue = dataHandler.storeData(dataList);

                fetchCount += batchSize;

                dataList.clear();

                if (!isContinue) {

                    break;

                }

            }

        }

 

        // 存储剩余数据

        if (CollectionUtils.isNotEmpty(dataList)) {

            dataHandler.storeData(dataList);

            fetchCount += dataList.size();

            dataList.clear();

        }

    }

 

    // 返回获取数量

    return fetchCount;

}

 

/** 使用案例 */

long fetchCount = odpsService.executeFetch("user", 5000, new DataHandler() {

    /** 解析数据 */

    @Override

public T parseData(Record record) {

        UserDO user = new UserDO();

        user.setId(record.getBigint("id"));

        user.setName(record.getString("name"));

        return user;

    }

    

    /** 存储数据 */

    @Override

public boolean storeData(List<T> dataList) {

        userDAO.batchInsert(dataList);

        return true;

    }

});

 

精简

 

public <T> long executeFetch(String tableName, int batchSize, Function<Record, T> dataParser, Function<List<T>, Boolean> dataStorage) throws Exception {

    // 构建下载会话

    DownloadSession session = buildSession(tableName);

 

    // 获取数据数量

    long recordCount = session.getRecordCount();

    if (recordCount == 0) {

        return 0;

    }

 

    // 进行数据读取

    long fetchCount = 0L;

    try (RecordReader reader = session.openRecordReader(0L, recordCount, true)) {

        // 依次读取数据

        Record record;

        List<T> dataList = new ArrayList<>(batchSize);

        while ((record = reader.read()) != null) {

            // 解析添加数据

            T data = dataParser.apply(record);

            if (Objects.nonNull(data)) {

                dataList.add(data);

            }

 

            // 批量存储数据

            if (dataList.size() == batchSize) {

                Boolean isContinue = dataStorage.apply(dataList);

                fetchCount += batchSize;

                dataList.clear();

                if (!Boolean.TRUE.equals(isContinue)) {

                    break;

                }

            }

        }

 

        // 存储剩余数据

        if (CollectionUtils.isNotEmpty(dataList)) {

            dataStorage.apply(dataList);

            fetchCount += dataList.size();

            dataList.clear();

        }

    }

 

    // 返回获取数量

    return fetchCount;

}

 

/** 使用案例 */

long fetchCount = odpsService.executeFetch("user", 5000, record -> {

        UserDO user = new UserDO();

        user.setId(record.getBigint("id"));

        user.setName(record.getString("name"));

        return user;

    }, dataList -> {

        userDAO.batchInsert(dataList);

        return true;

    });

```

 

普通的访问者模式,实现时需要定义DataHandler接口,调用时需要实现DataHandler匿名内部类,代码较多较繁琐。而精简后的访问者模式,充分利用了函数式编程,实现时无需定义接口,直接使用Function接口;调用时无需实现匿名内部类,直接采用lambda表达式,代码较少较简洁。

 

3. 代理模式

 

Spring中最重要的代理模式就是AOPAspect-Oriented Programming,面向切面的编程,是使用JDK动态代理和CGLIB动态代理技术来实现的。

 

普通

 

image.png 

 

精简1

 

基于@ControllerAdvice的异常处理:

 

image.png 

 

精简2

 

基于AOP的异常处理:

 

image.png


  接下篇:https://developer.aliyun.com/article/1227315?groupCode=java

相关文章
|
10天前
|
XML 安全 Java
Java反射机制:解锁代码的无限可能
Java 反射(Reflection)是Java 的特征之一,它允许程序在运行时动态地访问和操作类的信息,包括类的属性、方法和构造函数。 反射机制能够使程序具备更大的灵活性和扩展性
19 5
Java反射机制:解锁代码的无限可能
|
6天前
|
jenkins Java 测试技术
如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例详细说明
本文介绍了如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例,详细说明了从 Jenkins 安装配置到自动构建、测试和部署的全流程。文中还提供了一个 Jenkinsfile 示例,并分享了实践经验,强调了版本控制、自动化测试等关键点的重要性。
32 3
|
11天前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
41 10
|
7天前
|
分布式计算 Java MaxCompute
ODPS MR节点跑graph连通分量计算代码报错java heap space如何解决
任务启动命令:jar -resources odps-graph-connect-family-2.0-SNAPSHOT.jar -classpath ./odps-graph-connect-family-2.0-SNAPSHOT.jar ConnectFamily 若是设置参数该如何设置
|
5天前
|
Java
Java代码解释++i和i++的五个主要区别
本文介绍了前缀递增(++i)和后缀递增(i++)的区别。两者在独立语句中无差异,但在赋值表达式中,i++ 返回原值,++i 返回新值;在复杂表达式中计算顺序不同;在循环中虽结果相同但使用方式有别。最后通过 `Counter` 类模拟了两者的内部实现原理。
Java代码解释++i和i++的五个主要区别
|
13天前
|
搜索推荐 Java 数据库连接
Java|在 IDEA 里自动生成 MyBatis 模板代码
基于 MyBatis 开发的项目,新增数据库表以后,总是需要编写对应的 Entity、Mapper 和 Service 等等 Class 的代码,这些都是重复的工作,我们可以想一些办法来自动生成这些代码。
25 6
|
14天前
|
Java
通过Java代码解释成员变量(实例变量)和局部变量的区别
本文通过一个Java示例,详细解释了成员变量(实例变量)和局部变量的区别。成员变量属于类的一部分,每个对象有独立的副本;局部变量则在方法或代码块内部声明,作用范围仅限于此。示例代码展示了如何在类中声明和使用这两种变量。
|
15天前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
36 3
|
15天前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
24 1
|
17天前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。