記錄最近在項目設計中遇到的一個小問題。
前提:有這樣兩個POJO類,它們都可以通過鏈式調用的方式來設置其屬性值,其中一個類繼承了另一個類。
問題:通過鏈式調用,子類對象訪問父類方法後,如何使返回對象仍是子類對象,仍然可以繼續鏈式調用子類的方法?
結論:子類重寫父類中需要被調用的方法。在子類重寫的方法中,首先通過super關鍵字調用父類方法,
然後通過return this語句返回子類對象。
為了更具體、更形象的描述問題和解決辦法,上示例代碼。
BaseOption、AppearanceOption 是兩個實現了鏈式調用的POJO類,其中AppearanceOption 繼承自BaseOption。

1 package com.practice.option;
2
3 public class BaseOption {
4
5 private String id;
6
7 private String name;
8
9 public String getId() {
10 return id;
11 }
12
13 public String getName() {
14 return name;
15 }
16
17 public BaseOption setId(String id) {
18 this.id = id;
19 return this;
20 }
21
22 public BaseOption setName(String name) {
23 this.name = name;
24 return this;
25 }
26
27 }
View Code

1 package com.practice.option;
2
3 public class AppearanceOption extends BaseOption {
4
5 private String color;
6
7 private String shape;
8
9 private String size;
10
11 public String getColor() {
12 return color;
13 }
14
15 public String getShape() {
16 return shape;
17 }
18
19 public String getSize() {
20 return size;
21 }
22
23 public AppearanceOption setColor(String color) {
24 this.color = color;
25 return this;
26 }
27
28 public AppearanceOption setShape(String shape) {
29 this.shape = shape;
30 return this;
31 }
32
33 public AppearanceOption setSize(String size) {
34 this.size = size;
35 return this;
36 }
37
38 }
View Code
此時,AppearanceOption 類的對象調用父類的方法後,返回的是父類對象。
如下圖,setId()方法返回的是BaseOption對象,eclipse自動提示中看不到子類的方法。

修改子類AppearanceOption 的代碼,重寫父類方法。

1 package com.practice.option;
2
3 public class AppearanceOption extends BaseOption {
4
5 private String color;
6
7 private String shape;
8
9 private String size;
10
11 public String getColor() {
12 return color;
13 }
14
15 public String getShape() {
16 return shape;
17 }
18
19 public String getSize() {
20 return size;
21 }
22
23 public AppearanceOption setColor(String color) {
24 this.color = color;
25 return this;
26 }
27
28 public AppearanceOption setShape(String shape) {
29 this.shape = shape;
30 return this;
31 }
32
33 public AppearanceOption setSize(String size) {
34 this.size = size;
35 return this;
36 }
37
38 @Override
39 public AppearanceOption setId(String id) {
40 super.setId(id);
41 return this;
42 }
43
44 @Override
45 public AppearanceOption setName(String name) {
46 super.setName(name);
47 return this;
48 }
49
50 }
View Code
現在setId()方法返回的是AppearanceOption 對象,eclipse自動提示中可以看到子類的方法了。

從結論來看,並沒有用到多麼高深的技術,主要還是對面向對象特征的理解和運用。可是,在實際設計代碼結構的時候愣是半天沒想到。
主要的解決思路是來自Java源碼的啟發。在Java中,最常見的鏈式調用就是 StringBuffer、StringBuilder 類中的 append() 方法。我們可以通過連續的.append().append()方法來完成字符串的拼接。如果稍微熟悉源碼,可能會知道 StringBuffer、StringBuilder 這兩個類都繼承自抽象類AbstractStringBuilder,該抽象類中也有append() 方法。答案顯而易見了,查看一下 StringBuffer 或者 StringBuilder 的源碼就知道了。

由此想到的幾個問題,先留坑,想明白之後再來補充……
1.什麼情況下適合采用這種鏈式的方法調用?
2.對於項目來說,采用這種繼承結構是否合理?是否設計過度?