記錄最近在項目設計中遇到的一個小問題。app
前提:有這樣兩個POJO類,它們均可以經過鏈式調用的方式來設置其屬性值,其中一個類繼承了另外一個類。eclipse
問題:經過鏈式調用,子類對象訪問父類方法後,如何使返回對象還是子類對象,仍然能夠繼續鏈式調用子類的方法?ide
結論:子類重寫父類中須要被調用的方法。在子類重寫的方法中,首先經過super關鍵字調用父類方法,ui
而後經過return this語句返回子類對象。this
爲了更具體、更形象的描述問題和解決辦法,上示例代碼。 spa
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 }
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 }
此時,AppearanceOption 類的對象調用父類的方法後,返回的是父類對象。code
以下圖,setId()方法返回的是BaseOption對象,eclipse自動提示中看不到子類的方法。對象
修改子類AppearanceOption 的代碼,重寫父類方法。blog
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 }
如今setId()方法返回的是AppearanceOption 對象,eclipse自動提示中能夠看到子類的方法了。
從結論來看,並無用到多麼高深的技術,主要仍是對面向對象特徵的理解和運用。但是,在實際設計代碼結構的時候愣是半天沒想到。
主要的解決思路是來自Java源碼的啓發。在Java中,最多見的鏈式調用就是 StringBuffer、StringBuilder 類中的 append() 方法。咱們能夠經過連續的.append().append()方法來完成字符串的拼接。若是稍微熟悉源碼,可能會知道 StringBuffer、StringBuilder 這兩個類都繼承自抽象類AbstractStringBuilder,該抽象類中也有append() 方法。答案顯而易見了,查看一下 StringBuffer 或者 StringBuilder 的源碼就知道了。
擴展問題:
1.什麼狀況下適合採用這種鏈式的方法調用?
這裏使用的所謂鏈式調用,其實是同一個對象的多個方法的連續調用。也就是說,在這個長鏈中的每一個方法返回的都是相同的類型,相同的對象。例如,StringBuilder中append方法的連續調用,JSONObject中的accumulate、put等方法也能夠連續調用。這些被調用的方法都有「構建」的特性,都是用於完善實例對象。使用鏈式調用代碼容易編寫,看起來比較簡潔也容易閱讀和理解,但也應該注意代碼長度,適當換行。
若是被調用的方法返回的類型不一樣,則不適合鏈式調用。由於各方法返回的類型被隱藏了,代碼不容易理解,另外在Debug的時候也是比較麻煩的。
2.對於項目來講,採用這種繼承結構是否合理?是否設計過分?
對於簡單的POJO類來講,若是類中的屬性個數在十幾個之內,我以爲徹底不必用繼承。
若是各POJO類中屬性個數較多,重複的屬性也較多的狀況,能夠考慮使用繼承。
另外就是一些屬性的設置過程須要對外隱藏,或者須要對外使用統一的對象類型,這時能夠考慮使用繼承。
就本次項目而言,類的屬性值並無那麼多,我的認爲不須要搞那麼複雜。可是領導說「對外要使用統一的對象類型」,上層設計又不讓我插手。
因此,那就這樣吧~~~~~~