用静态工厂方法代替构造器

简介: 用静态工厂方法代替构造器

程序员这行干的久了,总会染上一些恶习,我就染上一个让人深恶痛绝,自己却津津乐道的习惯,还不想改的那种,它可以叫做强迫症,也可以叫做洁癖。那就是我不允许我的IDEA出现一点点警告,什么黄色背景,绿色波浪线,统统不允许,按下F2键必须是这样

当然,说这些也没有意义,因为并没有说如何去做,所以今天我准备开一个新的系列——如何写出高效清爽的Java代码,这意味着这整个系列的所有案例都会十分严谨且苛刻。如果有小伙伴说:这一丁点性能有什么嘛,无所谓啦。我:不,一丁点也不允许!

高效:开发高效,性能高效

今天是第一篇——使用静态工厂方法代替构造器

名字的重要性

一千个人眼里有一千个哈姆雷特,一千个项目里有个一千个通用响应对象,比如ApiResponseResponseResultBaseResult 等等,它们的结构一般都像这样

public class BaseResult<T> implements Serializable {
    private static final long serialVersionUID = -9127050844792378533L;
    /**
     * 状态码
     */
    private int code;
    /**
     * 消息
     */
    private String message;
    /**
     * 需要返回的数据对象
     */
    private T data;
    public BaseResult() {
    }
    public BaseResult(int code, String message) {
        this(code, message, null);
    }
    public BaseResult(int code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }
    // 省略get/set方法
}

一般我们会定义code为0,或者200什么的表示正确响应,其他的为错误响应。

使用的示例如下:

public BaseResult<Order> getOrder(){
  Order order = new Order();
  return new BaseResult<>(0, "成功", order);
}

这样子使用咋一看好像没什么问题,那是因为我先告诉大家code=0是正确,再给出相应的示例,如果小伙伴直接看示例多半会懵住:0是指什么?因为0在这里是个魔法值。或者说,正确的响应码发生变更,项目经理说,code=0太不好看了,改成200!这个时候...完蛋。

这时候我们可以多加一个专门用来描述code的类,如:

public interface ResultCode {
    /**
     * 正确响应码
     */
    int SUCCESS = 0;
    /**
     * 错误响应码
     */
    int FAILURE = -1;
}

使用方式就发生了变更:

public BaseResult<Order> getOrder(){
  Order order = new Order();
  return new BaseResult<>(ResultCode.SUCCESS, "成功", order);
}

现在,我们消除了魔法值,而且不管项目经理说把code改成啥都行,我们只改ResultCode.SUCCESS的值就行。

项目经理:code改成字符类型!

但是!如果每个接口的返回值都这样写,就会发现,整个项目都充斥这new BaseResult<>(ResultCode.SUCCESS, "成功", value)这样的语句,这一行代码只有value不一样,其他全都一模一样,啊,这丑陋的代码。

于是,我们继续改进,增加两个静态方法:

public static <T> BaseResult<T> success(T data){
  return new BaseResult<>(ResultCode.SUCCESS, ResultCode.SUCCESS_MESSAGE, data);
}
public static BaseResult<Void> failure(){
  return new BaseResult<>(ResultCode.FAILURE, ResultCode.FAILURE_MESSAGE);
}

在ResultCode类中增加两个常量:

String SUCCESS_MESSAGE = "成功";
String FAILURE_MESSAGE = "失败";

如果每次new BaseResult<>(ResultCode.SUCCESS, "成功", order)的话, 成功这个字符串则会随着每次new出BaseResult而创建出一个字符串对象。

改进后的使用方式:

public BaseResult<Order> getOrder(){
  Order order = new Order();
  return BaseResult.success(order);
}

使用者再也不需要关心code是啥,cool~

项目经理:给我把code改.... 开发:啪(巴掌声)

不必每次构建都创建对象

有时候调用的接口不需要返回参数,只需要响应一个正确或者失败即可,此时我们就需要一个无参的success方法:

public static BaseResult<Void> success(){
  return new BaseResult<>(ResultCode.SUCCESS, ResultCode.SUCCESS_MESSAGE);
}

使用:

public BaseResult<Void> createOrder(){
  return BaseResult.success();
}

不知道小伙伴有没有发现一个问题,这个无参的success方法每次返回的对象都是相同的,但是每次都创建了一个新的对象出来!啊,糟糕的代码!

改进:

public static final BaseResult<Void> SUCCESS = new BaseResult<>(ResultCode.SUCCESS, ResultCode.SUCCESS_MESSAGE);
public static final BaseResult<Void> FAILURE = new BaseResult<>(ResultCode.FAILURE, ResultCode.FAILURE_MESSAGE);
public static BaseResult<Void> success(){
  return SUCCESS;
}
public static BaseResult<Void> failure(){
  return FAILURE;
}

这里顺手把failure方法也改进一下

现在,每次调用无参success`方法时都使用一个静态对象,不再发生重复创建!爽!

注意,需要data数据的BaseResult不要这样做,否则会出现线程安全问题

闭环

有时候接口不仅会与页面交互,服务与服务之间也会产生交互,这时候如果我们想要判断其他接口的响应情况,会怎么做呢?

public void callOtherServer(){
  BaseResult<Void> result = createOrder();
  if(result.getCode() == ResultCode.SUCCESS){
    // 正确
  }
}

现阶段我们只能这样做,啊,这糟糕的代码又出现了!

改进:

public boolean isSuccess(){
  return this.code == ResultCode.SUCCESS;
}
public boolean isFailure(){
  return this.code != ResultCode.SUCCESS;
}

改进后的使用方式:

public void callOtherServer(){
  BaseResult<Void> result = createOrder();
  if(result.isSuccess()){
    // 正确
  }
}

优雅的代码!

小结

本篇介绍了关于使用静态工厂方法代替构造器的美好事情

第一:使用一个好名字对构造逻辑进行封装

第二:有时候并不需要每次重复的创建对象

第三:建立一个逻辑闭环

学会了的小伙伴看看自己的项目有没有改进的空间吧~

目录
相关文章
|
Java
构造方法
构造方法
56 0
|
Java
什么是构造器?
什么是构造器?
106 0
Zp
父类静态代码块、非静态代码块、构造方法、子类静态代码块、子类非静态代码块、子类构造方法执行顺序
父类静态代码块、非静态代码块、构造方法、子类静态代码块、子类非静态代码块、子类构造方法执行顺序
Zp
75 0
|
Java C++
C++类中在构造器中调用本类的另外构造器
C++类中在构造器中调用本类的另外构造器
99 0
|
Java C#
C# 构造方法
应用场景:1. 初始化(加载)对象 2. 初始化(加载)一些数据 特点:默认有一个无参构造方法
90 0
|
Python
8.2 类的构造器
class ren():     '''this class is about ren class。类的说明,使用三个单引号'''     def __init__(self,name,sex):        # 构造器         # 注意到 __init__ 方法的...
673 0
父类中如果没有无参构造方法(也即父类中只给了带参构造方法),子类的构造方法怎么办?
父类中如果没有无参构造方法(也即父类中只给了带参构造方法),子类的构造方法怎么办? /* 父类中如果没有无参构造方法(也即父类中只给了带参构造方法),子类的构造方法怎么办?   法1:子类的构造方法通过 super(...); 去显示调用父类的带参构造方法。
1173 0
Java反射 - 构造函数
Java反射——构造函数 使用Java反射,您可以检查类的构造函数,并在运行时实例化对象。 这是通过Java类java.lang.reflect.Constructor完成的。
818 0