范例(Examples)
下面是一段簡單程序,其中有兩個classes:表示[定單]的
Order和表示[客戶]的
Customer。
Order引用了
Customer,
Customer則并沒有引用
Order:
class Order...
Customer getCustomer() {
return _customer;
}
void setCustomer(Customer arg) {
_Customer = arg;
}
Customer _customer; //這是一個“Order”to “Customer”的連接
首先,我要為
Customer添加一個值域。由于一個客戶可以擁有多份定單,所以這個新增值域應該是個群集(collection)。我不希望同一份定單在同一個群集中出現一次以上,所以這里適合使用set:
class Customer {
private Set _orders = new HashSet();
現在,我需要決定由哪一個class負責控制關聯性(association)。我比較喜歡讓單一class來操控,因為這樣我就可以將所有[關聯處理邏輯]集中安置于一地。我將按照下列步驟做出這一決定:
- 如果兩者都是reference objects,而其間的關聯是[一對多]關系,那么就由[擁有單一reference]的那一方承擔[控制者]角色。以本例而言,如果一個客戶可擁有多份定單,那么就由Order class(定單)來控制關聯性。
- 如果某個對象是另一個對象的組成(component),那么由后者負責控制關聯性。
- 如果兩者都是reference objects,而其間的關聯是[多對多]關系,那么隨便其中哪個對象來控制關聯性,都無所謂。
本例之中由于Order負責控制關聯性,所以我必須為Customer添加一個賦值函數,讓Order可以直接訪問_orders(訂單)集群。
Order的修改函數(modifier)將使用這個輔助函數對指針兩端對象進行同步控制。我將這個賦值函數命名為friendOrders(),表示這個函數只能在這種特殊情況下使用。此外,如果
Order和
Customer位在同一個
package內,我還會將friendOrders()聲明為[package 可見度],使其可見程度降至最低。
但如果這兩個classes不在同一個package內,我就只好把friendOrders()聲明為
public了。
class Customer...
Set friendOrders() {
return _orders;
}
現在。我要改變修改函數(modifier),令它同時更新反向指針:
class Order...
void setCustomer(Custoemr arg) ...
if(_customer != null) _customer.friendOrders().remove(this);
_customer = arg;
if(_customer != null) _customer.friendOrders().add(this);
}
classes之間的關聯性是各式各樣的,因此修改函數(modifier)的代碼也會隨之有所差異。如果_customer的值不可能是null,我可
以拿掉上述的第一個null檢查,但仍然需要檢查引數(argument)是否是null。不過,基本形式總是相同的:先讓對方刪除[指向你]的指針,再
將你的指針指向一個新對象,最后讓那個新對象把它的指針指向你。
如果你希望在
Customer中也能修改連接(link),就讓它調用控制函數:
class Customer ...
void addOrder(Order arg) {
arg.setCustomer(this);
}
如果一份訂單也可以對應多個客戶,那么你所面臨的就是一個[多對多]情況,重構后的函數可能是下面這樣:
class Order ... //controlling methods
void addCustomer(Customer arg) {
arg.friendOrders().add(this);
_customers.add(arg);
}
void removeCustomer(Customer arg) {
arg.friendOrders().remove(this);
_customers.remove(arg);
}
class Customer ...
void addOrder(Order arg) {
arg.addCustomer(this);
}
void removeOrder(Order arg) {
arg.removeCustomer(this);
}