(149)Extract_Class
建立一個新Class,將相關的欄位和函式從就Class搬移到新Class
classDiagram
class Person{
string name
string officeAreaCode
string officeNumber
getTelephoneNumber()
}
轉換成
classDiagram
class Person{
string name
getTelephoneNumber()
}
class Telephone Number{
string areaCode
string number
getTelephoneNumber()
}
Person --> "1" Telephone Number: office Telephone
動機
常常聽到要有抽象性,但實際工作中,Class會不斷成長擴展,給某個Class添加一項新責任時,你會覺得不值得為這項責任分離出來一個單獨的Class。隨著責任不斷增加,這個Class會變得過分複雜,很快就亂了。
這樣個Class往往有大量的函式與資料,太大不容易理解,此時你要考慮哪個部分可以分離出去,並分離到另一個單獨的Class。
作法
- 決定如何分解Class所負責任
- 建立一個新Class,用以表現從舊Class中分離出來的責任
- 建立【從舊Class存取新Class】的連線關係。【白話:New 新Class】
- 使用(146)Move_Field搬移
- 使用(142)Move_Method將必要函式搬移到新Class。先搬移低階函式([被其他呼函式呼叫] 多於 [呼叫其他函式]),再搬較高函式。
- 決定是否讓新Class曝光。
範例
Class Person{
public string getName(){
return _name;
}
public string getTelephoneNumber(){
return ("(" + _officeAreaCode + ") " + _officeNumber);
}
string getOfficeAreaCode(){
return _officeAreaCode;
}
void setOfficeAreaCode(string arg){
_officeAreaCode = arg;
}
string getOfficeNumber(){
return _officeNumber;
}
void setOfficeNumber(string arg){
_officeNumber = arg;
}
private string _name;
private string _officeAreaCode;
private string _officeNumber;
}
步驟一
決定要搬移的範圍,移動欄位(146)Move_Field
``` cs
Class Person{
private string _name;
private string _officeNumber;
pribvate TelephoneNumber _officeTelephone = new TelephoneNumber();
public string getTelephoneNumber(){
return ("(" + _officeTelephone.getOfficeAreaCode() + ") " + _officeNumber);
}
public string getName(){
return _name;
}
string getOfficeNumber(){
return _officeNumber;
}
void setOfficeNumber(string arg){
_officeNumber = arg;
}
}
Class TelephoneNumber{
private string _officeAreaCode;
string getOfficeAreaCode(){
return _officeAreaCode;
}
void setOfficeAreaCode(string arg){
_officeAreaCode = arg;
}
}
第二步
移動其他欄位並且運用(142)Move_Method將相關函式移動到TelephoneNumber
Class Person{
private string _name;
pribvate TelephoneNumber _officeTelephone = new TelephoneNumber();
public string getTelephoneNumber(){
return _officeTelephone.getTelephoneNumber();_
}
public string getTeOfficelephone(){
return _officeTelephone;
}
public string getName(){
return _name;
}
}
Class TelephoneNumber{
private string _areaCode;
private string _number;
public string getTelephoneNumber(){
return ("(" + _areaCode + ") " + _number);
}
string getOfficeAreaCode(){
return _areaCode;
}
void setOfficeAreaCode(string arg){
_areaCode = arg;
}
string getOfficeNumber(){
return _number;
}
void setOfficeNumber(string arg){
_number = arg;
}
}
決定是否對外公開
如果決定公開就要特別考慮別名帶來的危險。如果暴露TelephoneNumber,而有人修改了_areaCode我怎麼知道?又可能呼叫的是其他人
有以下這幾種狀況:
-
完全公開TelephoneNumber。這就使得TelephoneNumber物件成為引用物件,使用(179)Change_Value_to_Reference。這種情況下,person應該是TelephoneNumber的存取點
-
不與任何人【不透過Person物件修改TelephoneNumber物件】。為了達到此目的,我可以將TelephoneNumber設為不可修改的,或為它提供一個不可修改的interface
後繼
(149)Extract_Class是改善程式的常用技術。因為它使你兩個Class分別加鎖。