Java 语言的几个缺陷之四: 过时的 JavaBean
曾几何时在业务分层结构中的 VO 或 DTO 层充斥着无数的标准 JavaBean 类, 那些碍手脚的 getter/setter 方法简值不忍直视. 或许 JavaBean 设定规范的用意是当某些属性为只读时不提供 setter 方法, 而实际使用时, 因 getter/setter 都同时具备, 那么 JavaBean 的所有私有属性又何异于公有属性呢.
更别说对于某些形式的属性名, 若属性名为
所以 Play Framework 1 以及 Play Framework 2.4.6 之前的版本采用了字节码增强的技术, 实现了像 Objective-C 的 @property 的特性, 即只要声明公有属性, 编译器为该属性生成默认的 getter/setter 方法, 您也可以手工去覆盖个别默认的 getter/setter 方法.
因此在 Play Framework 中书写的的 model 类就只需要属性了, 像
就这么简单, 想像一下如果我们为一个众多属性的 model 类补全所有的 getter/setter 方法读起来有多恐怖.
现在 Play Framework 来到了 Java 8, 函数式气味越来越浓, 也就不推荐为 model 类的所有属性自动产生 getter/setter 方法. 我们需要尽量的不可变性, 所以上面的类就变成了
把每一个属性都
Scala 的 case class
Scala 只要 case class User(id: Int, name: String, email: String, address: String) 这一行语句便有了一切, 属性是不可变的, 有了默认的构造函数, equals(), hashCode(), toString() 方法都自动有了.
Dart
由上可以看出其实 Dart 与 Java 对比并未改善多少, 只不过是省去了像
要说这方面算是 IntelliJ 的 Kotlin 向 Scala 学到不少, 来看看它是如何处理的
Kotlin
我要举报 Kotlin 抄袭了 Scala, 也有
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
更别说对于某些形式的属性名, 若属性名为
xCoordinate 时, 它所对应的 getter 方法分别是 getxCoordinate(),一般的 IDE 都会为它自动生成 getXCoordinate() 方法, 这是错误的. 实际上 getXCoordinate() 对应的属性名是 XCoordinate. 所以 Play Framework 1 以及 Play Framework 2.4.6 之前的版本采用了字节码增强的技术, 实现了像 Objective-C 的 @property 的特性, 即只要声明公有属性, 编译器为该属性生成默认的 getter/setter 方法, 您也可以手工去覆盖个别默认的 getter/setter 方法.
因此在 Play Framework 中书写的的 model 类就只需要属性了, 像
1public class User {
2 public int id;
3 public String name;
4 public String email;
5 public String address;
6}就这么简单, 想像一下如果我们为一个众多属性的 model 类补全所有的 getter/setter 方法读起来有多恐怖.
现在 Play Framework 来到了 Java 8, 函数式气味越来越浓, 也就不推荐为 model 类的所有属性自动产生 getter/setter 方法. 我们需要尽量的不可变性, 所以上面的类就变成了
1public class User {
2 public final int id;
3 public final String name;
4 public final String email;
5 public final String address;
6
7 public User(int id, String name, String email, String address) {
8 this.id = id;
9 this.name = name;
10 this.email = email;
11 this.address = address;
12 }
13}把每一个属性都
final 化之后, 我们就必须加上一个构造函数去初始化所有的 final 属性, 这个构造函数就是一个冗余的样板代码(Boilerplate code) 了. 当然目前 Java 还没有办法解决这个构造函数了, 但我们不妨学学 Scala, Dart 语言为声明一个上面的类是怎么做的.Scala 的 case class
1scala> case class User(id: Int, name: String, email: String, address: String)
2defined class User
3
4scala> User(1, "Yanbin", "fantasia@sina.com", "Chicago").name
5res17: String = YanbinScala 只要 case class User(id: Int, name: String, email: String, address: String) 这一行语句便有了一切, 属性是不可变的, 有了默认的构造函数, equals(), hashCode(), toString() 方法都自动有了.
Dart
1class User {
2 final int id;
3 final String name;
4 final String email;
5 final String address;
6
7 User(this.id, this.name, this.email, this.address);
8}
9
10var user = new User(100, "Yanbin", "fantasia@sina.com", "Chicago");
11print(user.id);
12user.name = "ChangeIt"; //报错 Uncaught TypeError: (intermediate value).set$name is not a function由上可以看出其实 Dart 与 Java 对比并未改善多少, 只不过是省去了像
this.name=name 那样的语句. 而且从上面的报错信息也能看出 dart 总是通过 set$xxx/get$xxx 来设置与获取值.要说这方面算是 IntelliJ 的 Kotlin 向 Scala 学到不少, 来看看它是如何处理的
Kotlin
1>>> class User(val id: Int, val name: String, val email: String, val address: String)
2>>> var user = User(100, "Yanbin", "fantasia@sina.com", "Chicago")
3>>> user.name
4Yanbin我要举报 Kotlin 抄袭了 Scala, 也有
var 和 val 之分, 不同之处是在声明类是 Scala 默认的属性是 val, 而 Kotlin 则必须指明 val 或 var, 没有 val/var 的话属性不可访问. 还有 Kotlin 没有像 Scala 的 case class 那样生成 equals(), hashCode(), 和 toString() 方法.
永久链接 https://yanbin.blog/java-language-defect-4-outdated-javabean/, 来自 隔叶黄莺 Yanbin's Blog[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。