这几天在做 Code Review 的时候,发现 Model 层内大量 Bean 写法不一。
有些类是属性开放一路 public,有些类则属性全部封闭 private。
大家针对这个问题讨论得还挺激动,着实出乎意料。
听他们的说辞,观点都挺有道理的。
封闭派支持者持以下观点。
Java 官方推荐针对实体类 Bean 进行封装,确保对外层调用者隐藏敏感数据。应该将类变量或属性声明为私有并提供公共获取及设置的方法,以便访问和更新私有变量的值。
的确。倘若一个属性是以 obj.field 的方式访问或直接赋值更新,当 field 的访问及更新逻辑需要调整时则得重新编写方法支持。
举个。
一个包含直接访问及更新变量的类如下。
Class Obj{
public int value;
}
Obj obj = new Obj();
//使用属性直接访问或更新
obj.value = -1;
int objValue = object.value;
而采用封闭开放原则编写的类为:
Class Obj{
private int value;
public void setValue(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
Obj obj = new Obj();
//使用方法调用的方式访问或更新
obj.setValue(-1);
int objValue = object.getValue();
当 Obj 希望限定 value 的值在大于等于 0 的值区间时需调整 Obj 类的实现。
Class Obj{
private int value;
//限定逻辑
public void setValue(int value){
if(value < 0){
value = 0;
}
this.value = value;
}
public int getValue(){
return this.value;
}
}
这样看起来,封闭派的写法确有前瞻性的。在未来,无论属性的访问及更新值逻辑要做怎样的调整,对于外部调用者而言是完全透明的。
开放派支持者其实并不反对封闭派的说辞,但针对封闭派所有 Bean 实体都写成这种格式,且看提交记录这些类大部分都已经两三年未修改的现状颇为不满。
有些用于描述 Android 设备信息,网络信息,App信息等固定内容的类,其属性并不会轻易进行修改。
想想也是,如AppInfo类用于描述 App 信息。
public class AppInfo{
public String appId;
public String versionName;
public String verionCode;
public String platform;
public String channel;
public String osVersion;
public String sdkVersion;
public String deviceId;
public String packageName;
}
在没有 JIT 场景下,直接字段访问要比调用 getter 方法快大约 3 倍;在有 JIT 场景下,直接字段访问要比方法调用快大约 7 倍。
当然。开放派支持者也会考虑该类的设计是否合理。
如上述变量 appId,希望在测试环境下追加一个 test 的后缀标识。
比如正式环境下 appId 值为 com.android.demo,测试环境则为 com.android.demo.test。
可调整为:
public class AppInfo{
public String appId;
//新增方法用于返回兼容后的 appId
public String getCompatAppId(){
if(BuildConfig.TEST){
return appId + ".test";
}
return appId;
}
}
又或者调整为:
public class AppInfoUtils{
//使用工具类对 appId 做二次转化
public getCompatAppId(String appId){
if(BuildConfig.TEST){
return appId + ".test";
}
return appId;
}
}
这两种方法都可。
开放派认为
- appId 属性不应该被轻易改动,没有必要过渡设计;
- 哪怕真的需要改动,改动也没有破坏属性的定义,可通过新增功能函数来解决这个问题即可。
一百个编程者心里有一百个哈姆雷特啊!
聊一聊我的看法。
在实际项目我确实也不会为所有 Bean 类编写 setter/getter 方法,因为会让代码变得冗余且调用相对麻烦。
但在封装设计SDK上,考虑到 SDK 维护及 API 更改的成本,还是遵循了开放封闭的设计原则,谨慎为好。
但代码看起来就是别扭呀。
好在Koltin解决了我内心的纠结。
对于 var 关键字申明的属性,gettter/setter是可选的,得益于幕后字段的设计,属性的访问及更新变为可干预的。
最后分享下最近有感的一句话
Fucking code, just happy!
欢迎关注 「Android之禅」公众号,和你分享有价值有思考的技术文章。
可添加微信 「Ming_Lyan」备注 “进群” 加入技术交流群,讨论技术问题严禁一切广告灌水。
如有 Android 领域有遇到技术难题亦或对未来职业规划有疑惑,一起讨论交流。
欢迎来扰。