代码细节
良好的命名
程序员最头疼的事情未必是业务代码的编写,后期开发命名往往会占用大部分时间,一个好的命名往往事半功倍,坏的命名总是让后来者忍不住吐槽,而实际工作中,大部分时间我也会纠结怎样给一个类命名,给一个方法命名,怎样给一个变量命名。这篇文档不仅仅是对工作的总结,更是以后对自己开发命名的要求。
变量名
变量名使用名词,一个好的变量名称,能展现出该变量的含义;
eg: String discountMoney // 折扣金额
String originPrice // 原价;
这种命名是不是不用注释就可以让阅读者一下就知道变量的含义,倘若我们的命名采用下面的例子,等到时间长了,是不是自己可能就不知道每个字段的含义了,还要通过翻业务代码一个个确认;
错误示意:
String money01;
String money02;
所以说命名之前想好含义,胜过自己的猜想。
函数名(方法名)
函数名要体现该函数的具体作用,而不是笼统的一个命名方式;
eg:
getUserInfo();
getUser();
第一个函数名能更直观的知道是获取用户信息的作用,第二个只是笼统的获取用户。
类名
类是对一类事务的抽取,应该体现出该类事务的准确性;
业务类名示意;
Student
Employee
针对一些非业务的辅助类,则应该尽量突出其辅助的作用;
辅助类示意:
AmountCalculationHelper;
包命
包作为类的文件夹,应该能反应类的共性
比如类名是Studet、Teacher、Assistant,那么包命是不是用people好一点,因为都是人物相关的。
模块名
模块代表整个模块的公用,在maven中,模块名也会显视的展现在依赖上;
可以参考spring中命名,controller、service、domain等;
形成固定的命名方式
我们在命名操作数据库的方法时,多少人命名方式会是insertXXX、updateXXX、deleteXXX、selectXXX,其实在实际开发中并不仅仅是这些,比如试下这种方式并且贯彻下去是不是更好理解呢。
名称前缀 备注
insert 插入
update 更新
delete 逻辑删除
remove 物理删除
get 获取单个结果
list 获取集合结果
count 计数
page 分页查询
。。。 。。。
当然更多的还是要在自己实际运用中去总结,并且形成自己的规范。
注释
注释不应当是对单词的描述,应该是对方法或者名称背后业务含义的说明;
代码规范
空行的重要性:
曾经和一起工作的同事关于空行有过争论,同一段pom以来引入或者是程序段中两个方法之间的空行的重要性,空行不仅仅能让代码的可读性更高,也能在解决冲突时,避免无必要的冲突;
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.blabla</groupId>
<artifactId>service</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/>
</parent>
<dependencies>
<!--启动依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.blabla</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--dubbo依赖-->
<dependency>
<groupId>io.dubbo.springboot</groupId>
<artifactId>spring-boot-starter-dubbo</artifactId>
<version>1.0.0</version>
</dependency>
<!--zookeeper依赖-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.7</version>
</dependency>
<!--连接数据库-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
if的细节抽取
代码中if的出现,如果仅仅是一个bool量的判断则无伤大雅,如果是一个多条件的组合,是不是抽取一个方法读起来可读性更高;
if (movements.getUserId().longValue() == userInfo.getUserId().longValue()) //if条件
if(isUser(userId))// 这样是不是更容易理解
简单的技巧
简单的细节
常量定义
-
针对应用级别的常量,建常量类;
-
针对业务级别的常量,建业务常量类;
-
针对类级别的常量,放在类的上方,以private开头;
示例为应用级别长量
package com.blabla.constants;/** * @author yzw * @date 2022/1/15 13:48 * @desc 应用级常量 */ public class CodeSkillConstant { /** * 逗号 */ public static final String COMMA = ","; }
方法的抽取
方法尽量不要采用超过30行,行数越多的方法意味着复用性越差,适当的抽取,保证功能单一,往往能提高代码的可读性和复用性;
util方法注释完整,功能尽可能做到单一,功能要充分测试验证;
字符串切割示例:
package com.blabla.util;
import org.springframework.util.StringUtils;
/**
* @author yzw
* @date 2022/1/15 13:47
* @desc 字符串工具类
*/
public class StringUtil {
/**
* 字符串切割
* @param original 传入字符串
* @param splitSymbol 切割符号
* @return
*/
public static String[] spiltStr(String original, String splitSymbol){
if(StringUtils.isEmpty(original)){
// 外部判空
return null;
}
return original.split(splitSymbol);
}
}
for循环的高效
-
代码中尽量不要出现三层for循环
-
for循环以大的集合进行转map或者set,在进行获取
package com.blabla;import com.blabla.pojo.User; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; /** * @author yzw * @date 2022/1/15 13:54 * @desc for循环转map的测试 */ public class ForEfficientTest { public static void main(String[] args) { List<User> userList = new ArrayList<>(); // 集合添加数据 addUser(userList); // 获取userId为blabla001的用户 保证用户id是唯一的 // 莱姆大表达式,其实内部也是循环for进行put,但是想一下多层for循环的时候,是不是只需要转一次就好了,效率也就上去了; // Collectors不仅能转map也能转set,set还具有去重的功能 Map<String, User> collect = userList.stream().collect(Collectors.toMap(User::getUserId, Function.identity())); System.out.println(collect.get("blabla001")); // 过滤大于40岁的人 List<User> collect1 = userList.stream().filter(user -> user.getAge() > 40).collect(Collectors.toList()); System.out.println(collect1); } private static void addUser(List<User> userList) { User user01 = new User("blabla001", "张三", 25); User user02 = new User("blabla002", "李四", 35); User user03 = new User("blabla003", "张三", 15); User user04 = new User("blabla004", "张三", 45); User user05 = new User("blabla005", "张三", 30); User user06 = new User("blabla006", "王五", 28); User user07 = new User("blabla007", "张三", 26); User user08 = new User("blabla008", "马六", 25); User user09 = new User("blabla009", "张三", 23); User user10 = new User("blabla010", "张三", 21); User user11 = new User("blabla011", "赵七", 25); User user12 = new User("blabla012", "张三", 25); User user13 = new User("blabla013", "张三", 24); User user14 = new User("blabla014", "张三", 25); userList.add(user01); userList.add(user02); userList.add(user03); userList.add(user04); userList.add(user05); userList.add(user06); userList.add(user07); userList.add(user08); userList.add(user09); userList.add(user10); userList.add(user11); userList.add(user12); userList.add(user13); userList.add(user14); } }
常量对象赋值
package com.blabla.constants;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author yzw
* @date 2022/1/15 13:48
* @desc 应用级常量
*/
public class CodeSkillConstant {
/**
* 逗号
*/
public static final String COMMA = ",";
/**
* 白名单,list初始化赋值示意
*/
public static final List<String> WHITE_LIST = new ArrayList<String>() {
{
add("blabla001");
add("blabla002");
add("blabla003");
}
};
public static final Map<String, String> VERSION_MAP = new HashMap<String, String>(4) {
{
put("version", "1.0.0");
}
};
}
简单的模式
策略模式:
定义:
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
解决的问题:
在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护
弊端:初入者感觉过重设计
应用场景:
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
图示
代码示例:
request:
package com.blabla.request;
import com.blabla.enums.CalculationType;
import lombok.Data;
/**
* @author yzw
* @date 2022/1/15 10:49
* @desc 计算请求体
*/
@Data
public class CalculationRequest {
/**
* 第一个数字
*/
private Integer firstNum;
/**
* 第二个数
*/
private Integer secondNum;
/**
* 操作方式
* @see CalculationType
*/
private String option;
}
controller
package com.blabla.controller;
import com.blabla.request.CalculationRequest;
import com.blabla.service.CalculationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author yzw
* @date 2022/1/15 10:42
* @desc 计算入口 策略模式示意
*/
@RestController
public class CalculationController {
@Autowired
private CalculationService calculationService;
@PostMapping("/calculate")
public Integer calculate(@RequestBody CalculationRequest request){
return calculationService.calculate(request);
}
}
service:
package com.blabla.service.impl;
import com.blabla.factory.CalculationBeanFactory;
import com.blabla.process.CalculationProcess;
import com.blabla.request.CalculationRequest;
import com.blabla.service.CalculationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author yzw
* @date 2022/1/15 10:55
* @desc
*/
@Service
@Slf4j
public class CalculationServiceImpl implements CalculationService {
@Override
public Integer calculate(CalculationRequest request) {
CalculationProcess calculationProcess = CalculationBeanFactory.getCalculationProcess(request.getOption());
return calculationProcess.calculationEasy(request.getFirstNum(), request.getSecondNum());
}
}
enum:
package com.blabla.enums;
/**
* @author yzw
* @date 2022/1/15 10:51
* @desc 计算类型枚举
*/
public enum CalculationType {
/**
* - 加减乘除
*/
ADD("ADD", "加法"),
SUB("SUB", "减法"),
MUL("MUL", "乘法"),
DIV("DIV", "除法"),
;
/**
* - 操作code
*/
private String code;
/**
* - 描述
*/
private String desc;
CalculationType(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
processInterface:
package com.blabla.process;
/**
* @author yzw
* @date 2022/1/15 10:57
* @desc 计算进程接口
*/
public interface CalculationProcess {
/**
* 简单计算方法
* @param firstNum
* @param secondNum
* @return
*/
Integer calculationEasy(Integer firstNum, Integer secondNum);
}
process:
package com.blabla.process;
import com.blabla.enums.CalculationType;
import com.blabla.factory.CalculationBeanFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
/**
* @author yzw
* @date 2022/1/15 10:58
* @desc 加法运算
* 实现InitializingBean 是为了类初始化是注册到工厂中做测略
*/
@Slf4j
@Component
public class AddCalculationProcess implements CalculationProcess, InitializingBean {
@Override
public Integer calculationEasy(Integer firstNum, Integer secondNum) {
return firstNum + secondNum;
}
@Override
public void afterPropertiesSet() throws Exception {
CalculationBeanFactory.registerCalculationProcess(CalculationType.ADD.getCode(), this);
}
}
package com.blabla.process;
import com.blabla.enums.CalculationType;
import com.blabla.factory.CalculationBeanFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
/**
* @author yzw
* @date 2022/1/15 11:05
* @desc 减法运算
*/
@Slf4j
@Component
public class SubCalculationProcess implements CalculationProcess, InitializingBean {
@Override
public Integer calculationEasy(Integer firstNum, Integer secondNum) {
return firstNum - secondNum;
}
@Override
public void afterPropertiesSet() throws Exception {
CalculationBeanFactory.registerCalculationProcess(CalculationType.SUB.getCode(), this);
}
}
....................
factory:
package com.blabla.factory;
import com.blabla.process.CalculationProcess;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author yzw
* @date 2022/1/15 10:56
* @desc 计算实体类工厂
*/
public class CalculationBeanFactory {
// 考虑线程安全
public static Map<String, CalculationProcess> calculationProcessMap = new ConcurrentHashMap<>();
public static CalculationProcess getCalculationProcess(String option){
CalculationProcess calculationProcess = calculationProcessMap.get(option);
return calculationProcess;
}
public static void registerCalculationProcess(String option, CalculationProcess calculationProcess){
calculationProcessMap.put(option, calculationProcess);
}
}
详细可看git项目:
项目地址:https://gitee.com/a-long-time-to-name-it/yzwselfproject.git