在Java的繼承中,你是否有這樣的疑惑?
一、問題
最近在寫代碼,有兩個屬性很相近的類,其中80%的屬性(字段)都是一樣的,剩下的才是各自不一樣的,在設(shè)計的時候,采用了繼承的方式,抽象除了一個父類,大概如下,
有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;
}
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;
}
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;
}
public String toString() {
return "SecondChild{" +
"secondField1='" + secondField1 + '\'' +
", secondField2='" + secondField2 + '\'' +
"} " + super.toString();
}
}
從上面可以看到兩個子類除了含有父類的屬性外還有自己各自的屬性,現(xiàn)在有個需求是這樣的,要實例化這兩個子類。
二、如何解決
2.1、分別初始化
何為分別初始化,所謂分別初始化就是各自初始化自己的,為每個子類分別實現(xiàn)初始化其屬性的方法,如下
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、抽象出一個公共的方法
既然,已經(jīng)為兩個子類抽象出了公共的屬性,那么順著這個思路下去,也可以抽象出一個公共的方法為這些公共的屬性賦值,即為父類填充屬性,
BaseDO fillField(BaseDO baseDO){
baseDO.setName("apple");
baseDO.setCode("apple");
return baseDO;
}
好了,在進行子類初始化的時候已經(jīng)有一個方法可以初始化其公共屬性,那么接下來的事情,就是初始化其自己的屬性即可,
下面就實例化FirstChild,然后初始化其公有屬性
FirstChild firstChild=new FirstChild();
fillField(firstChild);
firstChild.setMyField1("first Child");
System.out.println(firstChild);
打印出firstChild的結(jié)果如下
可以看到已經(jīng)把公共屬性name、code和特意屬性myField1進行賦值,完成了上面的需求。
可能有些同學會使用下面的寫法,
可以看的該種寫法存在錯誤,提示我們需要的類型是FirstChild,但是我們提供的BaseDO,我們知道fillField方法返回的BaseDO類型,一個父類型的實例不可賦值給子類型的引用( 相反一個子類型的實例可以賦值給父類型,典型的多態(tài) ),這怎么辦那,向下類型轉(zhuǎn)換,沒錯,如下
細心的小伙伴會問,那為什么fillField方法可以接受FirstChild的實例那,哈哈哈,前邊紅字提到了多態(tài)。
怎么樣,是不是對多態(tài)又有了更深的理解。
延申一點
從fillField方法來看,我們知道該方法可以不設(shè)返回值,為什么可以不設(shè)返回值,因為引用類型,不是傳值,可以理解為引用,哈哈,所以叫引用類型,在fillField方法中對其引用類型的參數(shù)進行了修改,那么在這個方法執(zhí)行完了之后,引用這個參數(shù)的其他引用同樣可以感知到其修改,下面的寫法就是很好的佐證,
是不是又加深了引用和引用的對象間的關(guān)系,多說一句引用在jvm的內(nèi)存模型中是在哪個區(qū),引用指向的對象那?
三、總結(jié)
本文分析了在開發(fā)過程中,遇到公有屬性很多的多個實體類時的設(shè)計思路,抽出公有的父類,由父類承擔公有屬性。并且在進行屬性填充的時候,如果公有屬性的值是一樣的,那么可以抽出公共的方法進行屬性填充,這里又提到了多態(tài)。
- 抽出公有屬性;
- 對多態(tài)的理解;
- 向下類型轉(zhuǎn)換;
- 引用類型的傳遞;
最后,廣大讀者們,對于類似的需求,你們有更好的設(shè)計思路嗎,歡迎踴躍討論。