目录
命名规范
局部变量管理
重复代码抽取
可复用模块独立
设计模式应用
分层架构设计
性能和易读权衡
命名规范
“计算机科学只存在两个难题:缓存失效和命名。” ——Phil KarIton
一个好的命名能够快速了解业务意图,见名知意是基本准则。毕竟代码是写给人看的,大家一定见过一些垃圾的命名,比如a,b,c,e,huoqu,gengxin等诸如此类的命名。那么怎么能让我们的命名更加规范,易懂、能懂呢?
像变量命名遵循驼峰规范,首字母大小写等基础的在这里不再赘述。在命名时我们可以借鉴一些大佬的命名,在java中我们可以以Spring框架代码为范本。下面讲解主要也是用Spring作为例子,在类、方法、变量三个方面进行阐述。
类
类是一个名词,所以在命名的时候需要用名词,不管是普通类、抽象类,还是接口。
下图是在ApplicationContext中处理生命周期bean的策略接口,当然如果使用了设计模式在最后加上模式名称,更能让读者快速明白作者的意图。
public interface LifecycleProcessor extends Lifecycle {
}
DefaultLifecycleProcessor是LifecycleProcessor的默认实现类,我们在不自己实现LifecycleProcessor的情况下,就会默认用到DefaultLifecycleProcessor的onRefresh和onCloseh。onRefresh作用是容器启动成功,onCloseh是只应用要关闭的时候。
public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactoryAware
方法
方法命名通常以动词+名词的形式,创建、获取、打开、刷新、准备,在关闭、在刷新等。
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
局部变量
局部变量命名通常是名词形式,表示一个存储的符号,名称能准确表达存在的内容。applicationArguments 表示应用参数,environment 表示配置环境,context表示上下文。
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
stopWatch.stop();
局部变量管理
尽量减少不必要的局部变量,声明没有意义的局部变量是在浪费我们的时间。
下图是创建上下文的代码,首先我们会用临时变量contextClass指向默认applicationContextClass,然后根据应用类型再指向具体的应用上下文,最后返回应用上下文对象。通过临时变量的方式来避免破坏原始数据。
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
变量在使用时候才声明,不能一下声明所有的局部变量,这样导致代码意图不明,加长占用内存资源的占用。
重复代码抽取
抽取重复代码通常是在开发过程中抽取,而不是等开发完后再进行。一边重构我们的代码,一边开发进行业务开发。一个类中的代码可以抽取成一个公共的方法,下面代码表示我们组装参数,发送数据,然后返回结果。
private ReportResult boughtOfficialCourse(String userId) {
getMarketingRecordEntity(userId);
SunshineInsurance.ReportResponse response = null;
try {
response = RestUtils.post(hostProperty.getSunshineInsuranceAds() + SUNSHINE_INSURANCE_REPORT_URL,
getBoughtOfficialRequestBody(new Long(userId)),
SunshineInsurance.ReportResponse.class);
} catch (Exception e) {
log.error("错误日志:", e);
}
return getResult(response);
}
封装个性方法组装参数getBoughtOfficialRequestBody()
//个性方法
private RequestBody getBoughtOfficialRequestBody(Long userId) {
RequestBodyBeforeEncrypt requestBodyBeforeEncrypt = new RequestBodyBeforeEncrypt();
RequestBody requestBody = new RequestBody();
requestBody.setOperation(OPERATION_INSERT);
requestBody.setData(AesUtils.encrypt(JsonUtils.toJson(requestBodyBeforeEncrypt), ENCRYPT_KEY));
return requestBody;
}
封装共性方法返回结果getResult()
//共性方法
@NotNull
private ReportResult getResult(ReportResponse response) {
if (response == null || response.getCode() != SUCCESS) {
return new ReportResult(false, response);
}
return new ReportResult(true, response);
}
设计模式应用
设计模式主要是对各个类进行编排,使其达到某种结构和应用效果的模式。比如工厂方法就是封装复杂对象的获取,装饰模式在不改变原有组件属性情况下动态添加属性,中介模式通过中介来统一交流避免每个节点的直连。模式的详细运用可以参看设计模式运用。
可复用模块独立
可复用模块的独立演进过程,通常是先抽取到单独的包目录下,使其成为项目内高内聚低耦合的通用模块,然后逐渐演化为可复用的公共组件,独立为单独的微服务。
如下我们有服务ABC,里面分别有用于消息通知的模块。服务A的模块是短信通知,服务B的模块是微信消息通知,服务C的模块是邮件消息通知。通过共性能力分析,将其沉淀为具有通用能力的公共组件,即消息通知中心。
分层架构设计
常见的架构设计模型中有分层架构、六边形架构、CQRS读写分离架构,其中用的比较多的就是分层架构。下图是领域驱动设计工程实践中常用的五层分层架构模型:
api接口层:是很薄的一层做参数校验和应用服务调用;
应用服务层:领域服务的流程编排和输出数据类型转换(do -> dto);
上下文:在领域服务中做数据流转的载体;
领域服务层:核心业务逻辑的处理;
基础设施层:包括仓储服务、缓存设施、消息队列等。
性能和易读权衡
“我们不应该把大量时间都耗费在哪些小的性能改进上;过早考虑优化是所有噩梦的根源”。我们最终编写的应该是清晰、简洁、易读和易理解的代码。真正优化需要留到后面,当性能测试或者性能分析我们哪些地方需要优化,优化后能有巨大的收益才进行。
如下setAge,addAge都用到了age抽取为一个变量age,可以避免两次getAge()带来的性能影响。但是能不用局部变量就不用局部变量,《重构——改善既有代码的设计》中有说到,尽量消除无用的局部变量,在不对局部变量进行修改时,都可以不声明这个变量。
int age = person.getAge();
logAge(age);
printAge(age);
可以用过两次调用 person.getAge()来消除无用的局部变量,其实多一次person.getAge()调用对java性能影响几乎为零。
logAge(person.getAge());
printAge(person.getAge());
参考资料:
《重构——改善既有代码的设计》
《Java性能权威指南》