范例(Examples)
在Replace Data Value with Object(175)一節中,我留下了一個重構后的程序,本節范例就從它開始。我們有下列的Customer class:
class Customer {
public Customer(String name) {
_name = name;
}
public String getName() {
return _name;
}
private final String _name;
}
它被以下的order class使用:
class Order...
public Order(String customer) {
_customer = new Customer(customer);
}
public String getCustomer() {
return _customer.getName();
}
public void setCustomer(String arg) {
_customer = new Customer(arg);
}
private Customer _customer;
此外,還有一些代碼也會使用Customer對象:
private static int numberOfOrdersFor(Collection orders, String customer) {
int result = 0;
Iterator iter = orders.iterator();
while(iter.hasNext()) {
Order each = (Order)iter.next();
if(each.getCustomer().equals(customer)) result ++;
}
return result;
}
到目前為止,Customer對象還是value object。就算多份定單屬于同一客戶,但每個order對象還是擁有各自的Customer對象。我希望改變這一現狀,使得一旦同一客戶擁有多份不同定單,代表這些定單的所有Order對象就可以共享同一個Customer對象。
首先我使用Replace Constructor with Factory Method(304)。這樣,我就可以控制Customer對象的創建過程,這在以后會是非常重要的。我在Customer class中定義這個factory method:
class Customer {
public static Customer create(String name) {
return new Customer(name);
}
}
然后我把[對構造函數的調用]替換成[對factory method的調用]:
class Order {
public Order(String customer) {
_customer = Customer.create(customer);
}
}
然后我再把構造函數聲明為private:
class Customer {
private Customer(String name) {
_name = name;
}
}
現在,我必須決定如何訪問Customer對象。我比較喜歡通過另一個對象(例如Order class中的一個值域)來訪問它。但是本例并沒有這樣一個明顯的值域可用于訪問Customer對象。在這種情況下,我通常會創建一個注冊(登錄)對象,作為訪問點。為了簡化我們的例子,我把Customer對象保存在Customer class的一個static值域中,讓Customer class作為訪問點:
private static Dictionary _instance = new Hashtable();
然后我得決定:應該在接到請求時創建新的Customer對象,還是應該預先將它們創建好。這里我選擇后者。在應用程序的啟動代碼(start-up code)中,我先把需要使用的Customer對象加載妥當。這些對象可能來自數據庫,也可能來自文件。為求簡單起見,我在代碼中明確生成這些對象。反正以后我總是可以使用Substitute Algorithm(139)來改變它們的創建方式。
class Customer...
static void loadCustomers() {
new Customer("Lemon Car Hire").store();
new Customer("Associated Coffee Machines").store();
new Customer("Bilston Gasworks").store();
}
private void store() {
_instance.put(this.getName(), this);
}
現在,我要修改factory method,讓它返回預先創建好的Customer對象:
public static Customer create(String name) {
return (Customer)_instance.get(name);
}
由于create()總是返回既有的Customer對象,所以我應該使用Rename Method(273)修改這個factory method的名稱,以便強調(說明)這一點。
class Customer...
public static Customer getNamed(String name) {
return (Customer)_instances.get(name);
}