在开发过程中,我们一定会遇到这样一个场景:数据库创建一个表,再创建对应的实体类,最后再给实体类的每个字段赋值。
例如为实体类Aliyun 赋值
@Data
public class Aliyun {
public String appKey;
public String appSecret;
public String bucket;
public String endPoint;
}
方法一:手动set
public static void main(String[] args) {
Aliyun aliyun = new Aliyun();
aliyun.setAppKey("yourAppKey");
aliyun.setAppSecret("yourAppSecret");
aliyun.setBucket("yourBucket");
aliyun.setEndPoint("yourEndPoint");
}
方法二:copyProperties
public static void main(String[] args) {
// queryMap模拟前端传参
Map<String,Object> queryMap = new HashMap<>(16);
queryMap.put("appKey", "yourAppKey");
queryMap.put("appSecret", "yourAppSecret");
queryMap.put("bucket", "yourBucket");
queryMap.put("endPoint", "yourEndPoint");
Aliyun aliyun2 = new Aliyun();
BeanUtils.copyProperties(queryMap, aliyun2);
}
有的公司不建议使用这种写法,因为调试的时候比较棘手,例如appKey字段的值不对,我直接根据setAppKey就清楚知道哪里操作了该字段,你使用copyProperties,排查效率太低。
方法三: 链式编程
目标效果:
Aliyun aliyunInstance = Aliyun.options()
.setAppKey("yourAppKey")
.setAppSecret("yourAppSecret")
.setBucket("yourBucket")
.setEndPoint("yourEndPoint")
.build();
这样代码就干净很多,也很省事。这种风格就是链式编程,如何实现这种效果呢?
1. 创建实体类
/*
演示一个方法链编程风格
*/
public class Aliyun {
private String appKey;
private String appSecret;
private String bucket;
private String endPoint;
public static class Builder{
private String appKey;
private String appSecret;
private String bucket;
private String endPoint;
public Builder setAppKey(String appKey){
this.appKey = appKey;
return this;
}
public Builder setAppSecret(String appSecret){
this.appSecret = appSecret;
return this;
}
public Builder setBucket(String bucket){
this.bucket = bucket;
return this;
}
public Builder setEndPoint(String endPoint){
this.endPoint = endPoint;
return this;
}
public Aliyun build(){
return new Aliyun(this);
}
}
/**
* 调用Builder类
*/
public static Builder options(){
/*
创建对象
Aliyun.Builder demo = new Builder();
return demo;
简化为一句
*/
return new Aliyun.Builder();
}
/**
* 有参构造方法
*/
private Aliyun(Builder builder){
this.appKey = builder.appKey;
this.appSecret = builder.appSecret;
this.bucket = builder.bucket;
this.endPoint = builder.endPoint;
}
public String getAppKey() {
return appKey;
}
public String getAppSecret() {
return appSecret;
}
public String getBucket() {
return bucket;
}
public String getEndPoint() {
return endPoint;
}
@Override
public String toString() {
return "Aliyun{" +
"appKey='" + appKey + '\'' +
", appSecret='" + appSecret + '\'' +
", bucket='" + bucket + '\'' +
", endPoint='" + endPoint + '\'' +
'}';
}
}
单元测试
public static void main(String[] args) {
// 这种写法无法修改设置的参数
Aliyun aliyunInstance = Aliyun.options()
.setAppKey("yourAppKey")
.setAppSecret("yourAppSecret")
.setBucket("yourBucket")
.setEndPoint("yourEndPoint")
.build();
}
这种写法有个局限性,就是一旦set值后,无法再修改该实例的字段值 。这种局限性有利有弊。
先说弊端,肯定是拓展性太差,日常业务避免不了修改此实例的字段值。
优化:可以对同一实例再次set字段值
// 可以修改参数的写法
Aliyun.Builder builder = Aliyun.options()
.setAppKey("yourAppKey")
.setAppSecret("yourAppSecret")
.setBucket("yourBucket")
.setEndPoint("yourEndPoint");
Aliyun aliyunInstance2 = builder.setAppKey("myAppKey").build();
Bean的玩法
再来说说好处
例如我们有一个配置文件,配置文件有4个参数,我们需要读取配置文件的四个参数,赋值给该类。并将这个类声明为一个bean,以后哪里需要配置文件的参数值,直接注入这个bean,使用起来相当方便
例如一个application.properties配置文件
appKey=1
appSecret=1
bucket=lynn
endPoint=https://www.aliyun.com
第一步:创建Aliyun实体类,同上
第二步:读取配置参数,写入实体类,声明为Bean
/**
* 读取配置信息,将参数写入到类中,并将该类声明为一个Bean托管
*/
@SpringBootConfiguration
public class statementBean {
@Value("${appKey}")
private String appKey;
@Value("${appSecret}")
private String appSecret;
@Value("${bucket}")
private String bucket;
@Value("${endPoint}")
private String endPoint;
@Bean
public Aliyun aliyun(){
return Aliyun.options()
.setAppKey(appKey)
.setAppSecret(appSecret)
.setBucket(bucket)
.setEndPoint(endPoint)
.build();
}
}
第三步:注入Bean,使用参数
/**
* 获取Bean并使用
*/
@Service
public class userBean {
@Autowired
private Aliyun aliyun;
public void printStr(){
System.out.println(aliyun.getAppKey());
System.out.println(aliyun.getBucket());
System.out.println(aliyun.getAppSecret());
System.out.println(aliyun.getAppSecret());
}
}
这时有人会质疑,直接 @Value(“${appKey}”)取出来后用就行了,多搞一个Bean出来,岂不是多此一举。
针对这个问题,现在只是取出来配置文件的个别参数,实际项目中会有上百个参数等待使用,那么你用时得取一次,他用时得取一次,且不方便管理。现在我只需要创建一个配置类的包,里面创建一些配置类,这些配置类中存放着配置文件的值。谁要用直接注入对应的Bean即可。这多方便处理。
此外,这种链式风格的写法,还起到了限制作用。一旦配置文件的值被存入aliyunInstance 这个实例,那么该实例的值就无法被修改。我们在配置文件的值当然不允许被修改了。
以前用全局变量声明public static final String appkey2 = "yourAppKey";
,为了方便管理,于是在配置文件application.properties中定义
// 这种写法无法修改设置的参数
Aliyun aliyunInstance = Aliyun.options()
.setAppKey("yourAppKey")
.setAppSecret("yourAppSecret")
.setBucket("yourBucket")
.setEndPoint("yourEndPoint")
.build();
}
当然,这只是一代码建议,多试试不同的写法就当锻炼代码能力