一、數(shù)據(jù)、對象的反對稱性
對象:將數(shù)據(jù)隱藏于抽象之后,暴露操作數(shù)據(jù)的函數(shù)。
數(shù)據(jù)結(jié)構:暴露數(shù)據(jù)本身,不提供有意義的函數(shù)。
例如下面:
public class Point {
public double x;
public double y;
}
public interface Point {
double getX();
double getY();
void setCartsian(double x,double y);
double getR();
double getTheta();
void setPolar(double r,double theta);
}
一個暴露了實現(xiàn),一個完全隱藏了實現(xiàn)。但是該接口還是呈現(xiàn)了一種數(shù)據(jù)結(jié)構。隱藏實現(xiàn)并非只是在變量之上加一層函數(shù)層。隱藏實現(xiàn)關乎抽象!類并不是簡單用存儲器和賦值器,而是暴露抽象接口嗎,讓用戶無須了解數(shù)據(jù)的實現(xiàn)就能操作數(shù)據(jù)<b>本體</b>。
public interface Vehicle {
double getFuelTankCapacityInGallons();
double getGallonsOfGasoline();
}
public interface Vehicle {
double getPercentFuelRemaining();
}
以上兩段代碼以后者為佳。我們不愿暴露數(shù)據(jù)細節(jié),更愿意以抽象的形態(tài)表述數(shù)據(jù)。<b>不要亂加取值器和賦值器,那是最壞的選擇。</b>
<b>過程式(使用數(shù)據(jù)結(jié)構的代碼)便于在不改動既有數(shù)據(jù)結(jié)構的前提下添加新函數(shù)。面向?qū)ο蟠a便于在不改動既有函數(shù)的前提下添加新類。</b>
反過來講也說得通:
<b>過程是代碼難以添加新的數(shù)據(jù)結(jié)構,因為必須修改所有函數(shù);面向?qū)ο蟠a難以添加新函數(shù),因為必須修改所有類。</b>
結(jié)論:一切對象都是傳說,有時候必須做一些過程式的操作。
二、得墨忒耳律
The Law of Demeter:模塊不應了解它操作對象的內(nèi)部情形。更準確地說,它認為類C的方法f只應該調(diào)用以下對象的方法:
- C
- 由f創(chuàng)建的對象;
- 作為參數(shù)傳遞給f的對象;
- 由C實體變量持有的對象。
方法不應該調(diào)用任何函數(shù)返回對象的方法,除非返回的是數(shù)據(jù)結(jié)構。即智能與朋友聊天,而與陌生人敬而遠之。
三、數(shù)據(jù)傳送對象
最為精煉的數(shù)據(jù)結(jié)構是只包含公有變量、沒有函數(shù)的類。這種結(jié)構有時被稱為數(shù)據(jù)傳送對象,DTO(Data Transfer Objects)。DTO是非常有用的結(jié)構,尤其是在與數(shù)據(jù)庫通信、或者套接字傳遞消息。更常見的是bean類的結(jié)構。豆結(jié)構擁有自否賦值器和取值器操作私有變量。這種半封裝會顯得更OO,當時通常沒有任何好處。