目录

命名规范

局部变量管理

重复代码抽取

可复用模块独立

设计模式应用

分层架构设计

性能和易读权衡


命名规范

“计算机科学只存在两个难题:缓存失效和命名。” ——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的模块是邮件消息通知。通过共性能力分析,将其沉淀为具有通用能力的公共组件,即消息通知中心。

java 多项目联调项目编码不同如何 项目编码可以重复吗_局部变量

分层架构设计

常见的架构设计模型中有分层架构、六边形架构、CQRS读写分离架构,其中用的比较多的就是分层架构。下图是领域驱动设计工程实践中常用的五层分层架构模型:

api接口层:是很薄的一层做参数校验和应用服务调用;

应用服务层:领域服务的流程编排和输出数据类型转换(do -> dto);

上下文:在领域服务中做数据流转的载体;

领域服务层:核心业务逻辑的处理;

基础设施层:包括仓储服务、缓存设施、消息队列等。

java 多项目联调项目编码不同如何 项目编码可以重复吗_编程语言_02

性能和易读权衡

“我们不应该把大量时间都耗费在哪些小的性能改进上;过早考虑优化是所有噩梦的根源”。我们最终编写的应该是清晰、简洁、易读和易理解的代码。真正优化需要留到后面,当性能测试或者性能分析我们哪些地方需要优化,优化后能有巨大的收益才进行。

如下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性能权威指南》