反向溝通 (IoC : Inversion Control )
2.3 主控者是框架,而不是應用程式
2.3 主控者是框架,而不是應用程式
前面說過,傳統的程式庫及類別庫只提供正向溝通,而應用框架則提供正向 和反向兼具的雙向溝通。本節針對應用框架的雙向溝通,做進一步的闡述雙向溝 通機制讓框架成為主控者,而應用程式只是配角而已。首先看個例子,假設已經 設計了Person 及 Customer 兩類別並存於應用框架中,如下圖所示:
Customer Person
(框架)
圖 2-2 一個簡單的框架
茲以Java 程式表達如下:
// Person.java
package _abstract_classes;
public abstract class Person { protected String name;
public void setName(String na) { name = na; } public abstract void display();
}
// Customer.java
package _abstract_classes;
public class Customer extends Person { public void display()
{ System.out.println("Customer: " + super.name); } }
40 Android應用框架原理與程式設計36 技
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
現在,基於這個框架而衍生出VIP 子類別,如下圖:
Customer Person
VIP
(應用程式) (框架)
圖 2-3 衍生出應用程式的類別
其Java 程式碼如下:
// VIP.java
package _concrete_classes;
import _abstract_classes.*;
public class VIP extends Customer { private String tel;
public VIP(String na, String t) { super.setName(na);
tel = t;
}
public void display() { super.display();
System.out.println("TEL: " + tel);
}}
第 2 章 應用框架魅力的泉源:反向溝通 41
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
建 構 式 VIP() 呼 叫 父 類 別 的 setName() 函 數 , 且 display() 呼 叫 Customer::display()函數,這兩者皆為正向溝通。亦即,程式中的函數呼叫框架中
的函數。現在繼續增添反向溝通機制。例如,於框架中增加了 Product 類別,此
時,框架共含三個類別。基於這框架,您可衍生出子類別如下圖所示:
Customer Person Product
pc
VIP TV
(應用程式) (框架)
圖 2-4 框架掌握更多主控權
其Java 程式碼如下:
// Product.java
package _abstract_classes;
public abstract class Product { protected int pno;
protected Customer cust;
public Product(int no) { pno = no; }
public void soldTo(Customer cobj) { cust = cobj; } public void inquire() {
this.print();
System.out.println("sold to ...");
cust.display();
}
42 Android應用框架原理與程式設計36 技
public class TV extends Product { private double price;
System.out.println("Price: " + price);
}}
public class TV extends Product { ....
public void print() ....
}}
public class Person { ....
第 2 章 應用框架魅力的泉源:反向溝通 43
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
import _concrete_classes.*;
public class JMain {
public static void main(String[] args) {
44 Android應用框架原理與程式設計36 技
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
這過程有個先決條件──VIP 類別必須覆寫 display()函數才行。否則將會呼叫 到 Customer 類別預設的 display(),而不是呼叫到 VIP 類別的 display()函數。也
許,您還會問一個問題:何不將cust 變數改宣告為 VIP 型態之參考呢﹖答案是:
別忘了,抽象類別通常設計在先,而具體類別產生在後。因之,設計 Product 類
別時,VIP 類別尚未誕生呢﹗ 這程式展現了應用框架的重要現象:
☉程式執行時,主控權在框架手上。
雖然 main()函數仍為程式的啟動者,但主要的處理過程皆擺在 Product 類別 內。例如,
● soldTo()負責搭配產品與顧客之關係。
● inquire() 負責呼叫 TV 的 print() 輸出產品資料,並呼叫 VIP 的 display() 輸出顧客資料。
☉程式裡的類別,其成員函數,主要是供框架呼叫之。
例如,TV 類別的 print()供 inquire()呼叫之,而 VIP 類別的 display()供 inquire() 呼叫之。
☉由於框架掌握主控權,複雜的指令皆擺在框架中,大幅簡化應用程式。
因之,優良的應用框架常讓程式師如虎添翼。
☉框架裡的inquire() 進行反向溝通,它呼叫子類別的 print() 函數。
這是同體系內的反向呼叫。
☉框架裡的inquire() 反向呼叫 VIP 的 display() 函數。
因 Product 與 VIP 分屬不同的類別體系。這是跨越體系的反向溝通。
第 2 章 應用框架魅力的泉源:反向溝通 45
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯