在Java 中如果要定義事件處理的方式,必須實作EventListener的子介面,例如實作 WindowListener來定義一些視窗事件的處理方式,WindowListener中定義了七個方法:
public
interface WindowListener extends EventListener {
public void windowOpened(WindowEvent e);
public void windowClosing(WindowEvent e);
public void windowClosed(WindowEvent e);
public void windowIconified(WindowEvent e);
public void windowDeiconified(WindowEvent e);
public void windowActivated(WindowEvent e);
public void windowDecativated(WindowEvent e);
}
public void windowOpened(WindowEvent e);
public void windowClosing(WindowEvent e);
public void windowClosed(WindowEvent e);
public void windowIconified(WindowEvent e);
public void windowDeiconified(WindowEvent e);
public void windowActivated(WindowEvent e);
public void windowDecativated(WindowEvent e);
}
可以定義一個類別來實作這個介面,以完全想要的事件處理,例如:
public
class WindowEventHandler implements WindowListener {
public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {}
public void windowClosed(WindowEvent e) {
System.exit(0);
}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDecativated(WindowEvent e) {}
}
public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {}
public void windowClosed(WindowEvent e) {
System.exit(0);
}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDecativated(WindowEvent e) {}
}
然而這有個缺點,實作介面的原則是您必須實作當中所定義的所有方法,即使您對某些事件並不感興趣,您也必須實作一個沒有內容的空方法,代表您已經實作了介 面中定義的方法,然而有時,您並不知道介面中到底定義了幾個方法,或是知道也不知道方法的確切名稱與參數,即使您查了API,在程式中寫下一堆沒有實作內 容的方法也是很煩人的一件事。
WindowAdapter類別預先實作了WindowListener介面,每個方法中都是空的實作,如下所示:
public
abstract class WindowAdapter
implements WindowListener {
public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDecativated(WindowEvent e) {}
}
implements WindowListener {
public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDecativated(WindowEvent e) {}
}
可以繼承WindowAdapter類別,並重新定義一些您所感興趣的事件,如此一來,就可以避開之前所提及的,直接實作 WindowListener介面的缺點,如下所示:
public
class WindowEventHandler extends WindowAdapter {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
}
public void windowClosed(WindowEvent e) {
System.exit(0);
}
}
這就是Default Adapter模式,它使用一個中介的Adapter類別來將真正感興趣的事件實作類別,配接至事件處理介面,上面的程式其 UML 圖如下:
將上圖一般化,Default Adapter模式的結構如下所示:
像Python這類的動態語言,沒有Java的interface這種機制來規範一個類別所需實作的介面,遵循物件之間的協定 基本上是開發人員的自我約束(當然,還得有適當的說明文件)。這邊可以反過來思考一下,如果你非得有個方式,強制實現某個公開協定,那該怎麼作?
可以類似這樣的寫法:
class
XDListener:
def action(self):
assert 0, 'action not implemented'
class Orz(XDListener):
def action(self):
print("XD")
orz = Orz()
orz.action()
def action(self):
assert 0, 'action not implemented'
class Orz(XDListener):
def action(self):
print("XD")
orz = Orz()
orz.action()
或者引發內建的NotImplementedError:
class
XDListener:
def action(self):
raise NotImplementedError("action not implemented")
class Orz(XDListener):
def action(self):
print("XD")
orz = Orz()
orz.action()
def action(self):
raise NotImplementedError("action not implemented")
class Orz(XDListener):
def action(self):
print("XD")
orz = Orz()
orz.action()
這樣的方式,在類別沒有重新定義指定方法時,至少在執行時期可以引起開發人員的注意,告訴他非得實作某個方法才行,如果你還想 要進一步阻止XDListener的實例化,則可以這麼實作:
class XDListener:
def __new__(clz):
raise NotImplementedError('Could not instantiate abstract ' + str(clz))
def action(self):
raise NotImplementedError("action not implemented")
def __new__(clz):
raise NotImplementedError('Could not instantiate abstract ' + str(clz))
def action(self):
raise NotImplementedError("action not implemented")
上例中,如果您試圖實例化XDListener,則會引發錯誤。或者你可以更進一步使用Python的特性:
from
abc import ABCMeta, abstractmethod
class XDListener(metaclass=ABCMeta):
@abstractmethod
def action(self):
pass
class Orz(XDListener):
def action(self):
print("XD")
orz = Orz()
orz.action()
class XDListener(metaclass=ABCMeta):
@abstractmethod
def action(self):
pass
class Orz(XDListener):
def action(self):
print("XD")
orz = Orz()
orz.action()
上例中,如果試圖實例化XDListener,則會發生TypeError:
TypeError: Can't instantiate abstract class
XDListener with abstract methods action
或者是子類別沒有實作所有被@abstractmethod修飾的方法,也會引發TypeError。例如若未實作 action()的話:
TypeError: Can't instantiate abstract class
Orz with abstract methods action