Re: [問題] setXXX
※ 引述《hougzou (該換個重訓方法了)》之銘言:
: ※ 引述《ChienHsiang (不務正業工程師)》之銘言:
: : 或許也可以把 Java Bean 的"習慣性用法"當成一種 Pattern 吧
: : 我覺得倒沒什麼誰對誰錯...
: : 何況很多以前大家認為錯的,現在又是那麼的理所當然...
: : Pattern Refactory後,又是一種新的Pattern不是嗎?
: 物件導向概念裡頭,有個大家都知道,卻都常忽略的概念,就是「封裝」。
: 這東西簡單來說,就是類別中的變數,不能給其他類別直接存取,而必須
: 提供setter/getter來設定或取得「變數值」。
: (注意!直接操作變數與間接取值是完全不同的兩回事)
: 這做法可以讓類別設計者能保留程式內容的彈性,當需求有變時,只需更改
: 類別內部對變數操作的方法,不用讓引用此類別的程式區段同時做修改。
: 至於為什麼要用setXXX以及getXXX。
: 如果某人的Java類別沒有重複利用的價值,那麼setXXX/getXXX改為任何有效的
: 方法名稱都可以。可是,如果這個類別有重複利用的可能,而且不知道會在
: 哪個領域用到,則採用getXXX/setXXX反而可以讓這隻類別提供Java Bean的功能。
: 不過之所以用set/get來當字首,簡單來說就是短、簡潔、易記。試想一下,
: 如果改用assignXXX/fetchXXX,是不是覺得很累綴哩?依學習以及使用的觀點
: 來看用set/get的確是種行為正確的選擇。
: 希望這些能解答討論串原PO的疑惑。
最近在重構 (Refactoring) 的時候遇到需要把所有直接存取的敘述全部改成 Getter 和
Setter 的情境,我正把一棵類別大爆炸 (超龐大) 的繼承樹引入裝飾者模式 (Decorator
Pattern),然而,若裝飾者繼承的元件含有可見的 (Visible, for instance: public,
protected) 成員變數,那麼裝飾者無法引導呼叫端使用內部元件的變數,而被誤用至裝
飾者本身的變數。
舉例而言:
/**
* 含有可見變數的元件
*/
public class Component {
// Oops! 可見的變數!!
public int properties;
// 複雜的計算會修改此物件的屬性
public int complexMethod(int param) {
return param + (properties++);
}
}
/**
* 元件的裝飾者
*/
public class Decorator extends Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
// 把計算委託給元件處理
public int complexMethod(int param) {
return component.complexMethod(param);
}
}
/**
* 錯誤的呼叫者
*/
public class Drive {
public static void main(String args[]) {
Component component = new Component();
Decorator decorator = new Decorator(component);
// 修改數值至裝飾者,但應修改至元件才對,錯誤!
decorator.properties = -1;
// 因為上面給值沒給到元件,所以這邊回傳的值不會反應到結果
int result = decorator.complexMethod(0);
// 期望 result 等於 -1, 但卻等於 0
}
}
=========================================================================
「封裝」是解決之道
=========================================================================
修改後的元件與裝飾者:
/**
* 包裝後的元件
*/
public class Component {
// 將此變數設為不可見 (private)
private int properties;
public int complexMethod(int param) {
return param + (properties++);
}
// Setter of properties
public void setProperties(int properties) {
this.properties = properties;
}
// Getter of properties
public int getProperties() {
return properties;
}
}
/**
* 元件的裝飾者
*/
public class Decorator extends Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
public int complexMethod(int param) {
return component.complexMethod(param);
}
@Override
public int getProperties() {
// 委託元件將屬性回傳
return component.getProperties();
}
@Override
public void setProperties(int properties) {
// 設定屬性至元件內
component.setProperties(properties);
}
}
/**
* 正確的呼叫者
*/
public class Drive {
public static void main(String args[]) {
Component component = new Component();
Decorator decorator = new Decorator(component);
// 透過 Setter 來設定元件的變數,正確!
decorator.setProperties(-1);
// 因為上面給值到元件,所以這邊回傳的值會反應到結果
int result = decorator.complexMethod(0);
// 期望 result 等於 -1, 確實地 result 正好等於 -1
}
}
引入裝飾者模式至一棵繼承樹必須確保所有的成員變數都是不可見 (invisible, for
instance: private) 的,否則無法阻止呼叫者修改裝飾者的變數,要達到所有的成員變
數都是不可見,請封裝您的元件變數,拒絕外面任何的使用者修改。
因此,請沒事就封裝您的成員變數 XD (無誤)
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.116.247.13
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 22 之 22 篇):