有時候不知道你會不會出現一些疑問?
當你為一些元件加入事件以後, 而這些元件產生變化的時候,
為什麼系統會知道是哪一個元件產生變化的呢?
其實他是由一種設計模式產生的, 這種設計模式稱作為”觀察者模式”
什麼叫做觀察者模式,
觀察者模式由三個角色所構成, 分別是觀察者、觀察者物件、主題物件,
假設有4個觀察者物件,其中3個觀察者物件加入了觀察者名單,
每當主題物件發布了某些訊息,
有加入觀察者名單的觀察者物件就會透過觀察者收到該訊息,
沒有加入觀察者名單的觀察者物件當然就不會收到訊息,
而如果已經在觀察者名單內的物件或者不在觀察者名單內的物件,
仍然可以自由的加入觀察者名單或者從觀察者名單內移除。
呵呵,有點頭昏腦脹了嗎?舉個白話點的例子,
現在假設大家都有玩過facebook的經驗,
而facebook有一種模式叫做粉絲團,
當你加入某一個粉絲團的時候, 當該粉絲團發布某項訊息時,
該粉絲團的粉絲都會收到這項訊息,
而當你退出這個粉絲團的時候, 就在也收不到該粉絲團的訊息了!
這樣就稱作一個觀察者模式。
現在把角色換成Button物件、Listener和Event物件,
Event物件就像是粉絲, Button物件的角色就像粉絲團,
當你把某一個Event物件加入了Button物件的Listener名單,
當button物件產生變化的時候, Listener就會去通知加入的Event物件。
button1.setOnClickListener(new OnClickListener(){
public void onClick(View v){
textView1.setText("textview1");
}
});
button1就是主題物件
setOnClickListener的行為就是加入觀察名單
new OnClickListener() 就是觀察者物件
當button產生變化的時候,
觀察者就去觀察者名單內查看有哪些觀察者物件加入,
然後逐一的通知它們。
我們來模擬一下Button按下去的情節,
這個程式用來模擬Android的Button按下的時候, 要處理什麼樣的動作,
首先你還是一樣要先宣告一個事件,然後把這個事件加入button的監聽器,
button1.setOnClickListener(new OnClickListener(){
public void onClick(View v){
textView1.setText("textview1");
}
});
可是我們模擬的button並不是android內建的,
如果要讓android顯示出來這兩個button,
還要在寫一些button的描述, 這樣太複雜了,
因此我們就真的宣告android內建的button,
當button按下的時候, 就去呼叫我們做出來的”假Button”裡面的”onclick”,
以達到模擬的效果。
而我們的重點放在模擬
android的button到底是怎麼實作出setOnClickListener()這個方法,
想像一下setOnClickListener是被Button的實體物件呼叫,
因此, 我們可以猜到上層Button這個類別一定有一個方法叫做setOnClickLister(),
並且會傳入OnClickListener這個物件的方法,
所以我們作出一個假button的類別,
interface FButton{
public void setOnClickListener(FakeOnLister listener);
}
這樣一來, 我們就可以知道有一個類別會繼承這個介面,
然後實作setOnClickListener這個方法。
在來我們想一下既然有傳入OnClickListener這個物件,
而且會實作onClick()這個方法
那麼我們也來定義一個假的Listener
interface FakeOnLister {
void onClick(int index);
}
由前面知道觀察者模式, 因此我們的Button裡面會出現幾個必要的方法,
首先是加入觀察者物件,移除觀察者物件,以及通知所有觀察者,
所以類別可以這樣寫出來,
class FakeButton implements FButton{
private List<FakeOnLister> listenerList;
public FakeButton(){
listenerList = new ArrayList<FakeOnLister>();
}
public void setOnClickListener(FakeOnLister listener) {
listenerList.add(listener);
}
public void removeOnClickListener(FakeOnLister listener){
int index = listenerList.indexOf(listener);
if(index>=0){
listenerList.remove(index);
}
public void onClick() {
for (int i=0; i<listenerList.size(); i++) {
listenerList.get(i).onClick(i);
}
}
}
加入觀察者物件
public void setOnClickListener(FakeOnLister listener)
移除觀察者物件
public void removeOnClickListener(FakeOnLister listener)
通知所有觀察者
public void onClick()
所以可以開始使用這個”假Button”了
private FakeButton fakeButton1;
private FakeButton fakeButton2;
public void onCreate(Bundle savedInstanceState) {
fakeButton1 = new FakeButton();
fakeButton2 = new FakeButton();
fakeButton1.setOnClickListener(new FakeOnLister(){
@Override
public void onClick(int index) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(),
"button1 click",
Toast.LENGTH_SHORT).show();
}
});
fakeButton2.setOnClickListener(new FakeOnLister(){
@Override
public void onClick(int index) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(),
"button2 click",
Toast.LENGTH_SHORT).show();
}
});
}
當我們按下假button 1號就會印出Log訊息顯示我們按下的是假button 1號
同理, 假button 2號。
接著我們重複剛剛所說的用真的button去模擬我們寫出來的假button,
借用一下他們的onClick動作來證實我們的button是可以動的。
button1 = (Button)findViewById(R.id.a_button);
button2 = (Button)findViewById(R.id.b_button);
button1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
fakeButton1.onClick();
}
});
button2.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
fakeButton2.onClick();
}
});
如此一來, 我們可以在畫面看到兩個button,
當按下去的時候, 的確可以跑到我們一開始所期望的情況。