java---爲什麼要有bean

Java語言欠缺屬性、事件、多重繼承功能。所以,如果要在Java程序中實現一些面向對象編程的常見需求,只能手寫大量膠水代碼。Java Bean正是編寫這套膠水代碼的慣用模式或約定。這些約定包括getXxx、setXxx、isXxx、addXxxListener、XxxEvent等。遵守上述約定的類可以用於若干工具或庫。

舉個例子,假如有人要用Java實現一個單向鏈表類,可能會這樣寫:

// 編譯成 java-int-list_1.0.jar
public final class JavaIntList {
  static class Node {
    public Node next;
    public int value;
  }
  public Node head;
  public int size;
}

上述實現爲了能夠快速獲取鏈表的大小,把鏈表大小緩存在size變量中。用法如下:

JavaIntList myList = new JavaIntList();
System.out.println(myList.size);

JavaIntList的作者很滿意,於是開源了java-int-list庫的1.0版。文件名是java-int-list_1.0.jar。發佈後,吸引了許多用戶來使用java-int-list_1.0.jar。
有一天,作者決定要節省內存,不要緩存size變量了,把代碼改成這樣:

// 編譯成 java-int-list_2.0.jar
public final class JavaIntList {
  static final class Node {
    public Node next;
    public int value;
  }
  public Node head;
  public int getSize() {
    Node n = head;
    int i = 0;
    while (n != null) {
      n = n.next;
      i++;
    }
    return i;
  }
}

然後發佈了2.0版:java-int-list_2.0.jar。發佈後,原有java-int-list_1.0.jar的用戶紛紛升級版本到2.0。這些用戶一升級,就發現自己的程序全部壞掉了,說是找不到什麼size變量。於是這些用戶就把作者暴打一頓,再也不敢用java-int-list庫了。

這個故事告訴我們,如果不想被暴打致死,你就必須保持向後兼容性。太陽公司在設計Java語言時,也懂得這個道理。所以Java標準庫中,絕對不會出現public int size這樣的代碼,而一定會一開始就寫成:

private int size;
public int getSize() { return size; }

讓用戶一開始就使用getSize,以便有朝一日修改getSize實現時,不破壞向後兼容性。這種public int getSize() { return size; }的慣用手法,就是Java Bean。

現在是2014年,C#、Scala等比Java新的面嚮對象語言自身就提供了語言特性來實現這些常用需求,所以根本不需要Java Bean這樣繁瑣的約定。

比如,假如有個Scala版的ScalaIntList:

// 編譯成 scala-int-list_1.0.jar
object ScalaIntList {
  final case class Node(next: Node, value: Int)
}
final class ScalaIntList {
  var head: ScalaIntList.Node = null
  var size: Int = 0
}

用戶這樣用:

val myList = new ScalaIntList
println(myList.size)

有一天你心血來潮改成這樣:

// 編譯成 scala-int-list_2.0.jar
object ScalaIntList {
  final case class Node(next: Node, value: Int)
}
final class ScalaIntList {
  var head: ScalaIntList.Node = null
  final def size: Int = {
    var n = head
    var i = 0
    while (n != null) {
      n = n.next
      i++
    }
    i
  }
}

用戶還是照樣能用,根本不破壞向後兼容性。所以Scala程序只要不考慮和Java交互,一般就不需要類似Java Bean這樣的約定。

順便說一句,向後兼容性分爲源代碼級和二進制級,Scala的var或val改爲final def的話,無論源代碼級的向後兼容性,還是二進制級的向後兼容性,都不遭受破壞。但C#的字段改爲屬性的話,雖然不破壞源代碼級的向後兼容性,但是會破壞二進制級的向後兼容性。這是C#的設計缺陷,導致微軟的編碼規範不得不禁止使用公有字段。

 

 

總的來說:

1、所有屬性爲private
2、提供默認構造方法
3、提供getter和setter
4、實現serializable接口

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章