• 沒有找到結果。

主控者是框架,而不是應用程式

反向溝通 (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

¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯