一、問題
最近在寫程式碼,有兩個屬性很相近的類,其中80%的屬性(欄位)都是一樣的,剩下的才是各自不一樣的,在設計的時候,採用了繼承的方式,抽象除了一個父類,大概如下,
有FirstChild和SecondChild兩個類,因為其中的屬性name、code等是相同的,為此抽出了一個父類BaseDO,如下
package com.example.day01; public class BaseDO { private String name; private String code; private String field1; private String field2; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public String getField2() { return field2; } public void setField2(String field2) { this.field2 = field2; } @Override public String toString() { return "BaseDO{" + "name='" + name + '\'' + ", code='" + code + '\'' + ", field1='" + field1 + '\'' + ", field2='" + field2 + '\'' + '}'; } }
FirstChild
package com.example.day01; public class FirstChild extends BaseDO{ private String myField1; private String myFiled2; public String getMyField1() { return myField1; } public void setMyField1(String myField1) { this.myField1 = myField1; } public String getMyFiled2() { return myFiled2; } public void setMyFiled2(String myFiled2) { this.myFiled2 = myFiled2; } @Override public String toString() { return "FirstChild{" + "myField1='" + myField1 + '\'' + ", myFiled2='" + myFiled2 + '\'' + "} " + super.toString(); } }
SecondChild
package com.example.day01; public class SecondChild extends BaseDO{ private String secondField1; private String secondField2; public String getSecondField1() { return secondField1; } public void setSecondField1(String secondField1) { this.secondField1 = secondField1; } public String getSecondField2() { return secondField2; } public void setSecondField2(String secondField2) { this.secondField2 = secondField2; } @Override public String toString() { return "SecondChild{" + "secondField1='" + secondField1 + '\'' + ", secondField2='" + secondField2 + '\'' + "} " + super.toString(); } }
從上面可以看到兩個子類除了含有父類的屬性外還有自己各自的屬性,現在有個需求是這樣的,要例項化這兩個子類。
二、如何解決
2.1、分別初始化
何為分別初始化,所謂分別初始化就是各自初始化自己的,為每個子類分別實現初始化其屬性的方法,如下
FirstChild fillFirstField(FirstChild firstChild){ firstChild.setName("apple"); firstChild.setCode("apple"); firstChild.setMyField1("first Child"); return firstChild; }
SecondChild fillSecondField(SecondChild secondChild){ secondChild.setName("apple"); secondChild.setCode("apple"); secondChild.setSecondField1("second Child"); return secondChild; }
這裡作為演示對屬性沒有全部賦值,如果兩個子類相同的屬性比較多,那麼賦值起來會比較麻煩,而且兩個方法的程式碼重複度會很高。
2.2、抽象出一個公共的方法
既然,已經為兩個子類抽象出了公共的屬性,那麼順著這個思路下去,也可以抽象出一個公共的方法為這些公共的屬性賦值,即為父類填充屬性,
BaseDO fillField(BaseDO baseDO){ baseDO.setName("apple"); baseDO.setCode("apple"); return baseDO; }
好了,在進行子類初始化的時候已經有一個方法可以初始化其公共屬性,那麼接下來的事情,就是初始化其自己的屬性即可,
下面就例項化FirstChild,然後初始化其公有屬性
FirstChild firstChild=new FirstChild(); fillField(firstChild); firstChild.setMyField1("first Child"); System.out.println(firstChild);
列印出firstChild的結果如下
可以看到已經把公共屬性name、code和特意屬性myField1進行賦值,完成了上面的需求。
可能有些同學會使用下面的寫法,
可以看的該種寫法存在錯誤,提示我們需要的型別是FirstChild,但是我們提供的BaseDO,我們知道fillField方法返回的BaseDO型別,一個父型別的例項不可賦值給子型別的引用(相反一個子型別的例項可以賦值給父型別,典型的多型),這怎麼辦那,向下型別轉換,沒錯,如下
細心的小夥伴會問,那為什麼fillField方法可以接受FirstChild的例項那,哈哈哈,前邊紅字提到了多型。
怎麼樣,是不是對多型又有了更深的理解。
延申一點
從fillField方法來看,我們知道該方法可以不設返回值,為什麼可以不設返回值,因為引用型別,不是傳值,可以理解為引用,哈哈,所以叫引用型別,在fillField方法中對其引用型別的引數進行了修改,那麼在這個方法執行完了之後,引用這個引數的其他引用同樣可以感知到其修改,下面的寫法就是很好的佐證,
是不是又加深了引用和引用的物件間的關係,多說一句引用在jvm的記憶體模型中是在哪個區,引用指向的物件那?
三、總結
本文分析了在開發過程中,遇到公有屬性很多的多個實體類時的設計思路,抽出公有的父類,由父類承擔公有屬性。並且在進行屬性填充的時候,如果公有屬性的值是一樣的,那麼可以抽出公共的方法進行屬性填充,這裡又提到了多型。
1、抽出公有屬性;
2、對多型的理解;
3、向下型別轉換;
4、引用型別的傳遞;
最後,廣大讀者們,對於類似的需求,你們有更好的設計思路嗎,歡迎踴躍討論。