天天看點

詳解 JAVA 适配模式和 接口擴充卡

 JAVA适配模式

<a>意圖 将一個類的接口轉換成客戶希望的另外一個接口。Adapter模式使得原本由于接口不相容而不能一起工作的那些類可以一起工作。(GoF) 場景 相信很多人都知道什麼是顯示卡,也有很多人知道顯示卡的本名——圖形擴充卡。恩,是的,正好這回說說Apater模式,就拿顯示卡來例子來分析一下Adapter模式。 我們知道顯示器(Client)是用來顯示圖形的,它是不能顯示資料,它隻能夠接受來自圖形發送裝置Target的信号。可是我們手頭上隻有CPU(Adaptee)這個産生各種描述圖形的資料的資料發送器。我們需要将這些資料讓顯示器進行顯示,可是這兩個部件卻是不相容的。于是我們需要一個中間裝置,它能夠将CPU“适配”于顯示器,這便是我們的顯示卡——圖形擴充卡(Adapter)。</a>

java 代碼

// 圖形發送裝置 

public class Target { 

    publicString request() { 

       return "Graphic sender"; 

   } 

    //顯示器 

    public classClient { 

       public static void main(String[] args) { 

           Target target = new Targete(); 

           System.out.println(target.request()); 

       } 

可是我們的CPU(Adaptee)隻能輸出0/1資料,他是個電腦,而不是圖形發送裝置(Target)。

    //CPU 

    public classAdaptee { 

       public String getData() { 

           return "CPU data"; 

這個時候我們的顯示卡(Adapter)的作用便展現出來了,它負責對CPU進行适配,通過将CPU傳過來的資料轉換成圖形信号,進而将CPU僞裝成一個圖形發送裝置。

    //顯示卡,即我們的擴充卡 

    public classAdapter extends Target { 

       // 被代理的裝置 

       private Adaptee apt = null; 

       public Adapter(Adaptee apt) { 

           this.apt = apt; 

       public String request() { 

           return apt.getData(); 

這樣,我們的電腦的顯示流程就變成CPU-顯示卡-顯示器:

    public class Client { 

           // CPU經過顯示卡的适配後“變”成了圖形發送裝置了 

           Target target = new Adapter(new Adaptee()); 

上面的這種依賴于對象組合的Adapter模式叫做對象擴充卡(ObjectAdapter)。它的特征是繼承/實作某一方的類(Target),如這裡的圖形發送器,同時内部包含一個被适配的類(Adaptee),如這裡的CPU。通過重寫其父類的方法來進行适配。

另一種的Adapter實作

對于Adapter模式,還有另外一種實作方式,這種适配方式叫做類擴充卡(ClassAdapter)。它與Object Adapter的不同之處在于它繼承被适配的對象。

    public classAdapter extends Targer, Adaptee { 

       ...... 

這樣的代碼在C++中是合法的,但是在Java中規定最多隻能繼承一個父類,而可以實作多個接口。是以我們需要建立一個IAdaptee的接口,然後将我們的Adapter繼承Target同時實作IAdaptee。

    //IAdaptee接口 

    publicinterface IAdaptee{   

       String getData(); 

   }  

    // Adaptee實作IAdaptee

    public classAdaptee implements IAdaptee { 

     ...... 

   }   

    public classAdapter extends Target implements IAdaptee{ 

       private IAdaptee apt = null; 

       public Adapter(IAdaptee apt) { 

對于我們的顯示器(Client)方面,Class Adapter跟Object Adapter一樣,是以不需要進行修改。

對于ClassAdapter,大家也看見了,在Adapter中因為是實作了IAdaptee接口,是以需要實作getData()的接口。一旦Target和IAdaptee擁有相同的方法時,會出現麻煩的。是以盡量優先使用ObjectAdapter的模式。

接口擴充卡

java中擴充卡的作用實際上是實作了接口的類,但是擴充卡所實作的隻是空方法。因為如果我們不用擴充卡,直接去實作接口,也要逐個實作裡面的方法,并且大多情況下我們也會像jdk裡擴充卡所做的:僅僅以空方法去實作,隻實作對我們有用的方法。 

幾乎所有申明了很多方法 的接口,都會有它自己的 擴充卡類。 

本身adapter沒有什麼作用,隻是幫助程式員專注 所實作的功能,使代碼簡潔罷了

舉第一個例子:

為一個接口提供預設實作,這樣子類可以從這個預設實作進行擴充.而不必從原有接口進行擴充.作為擴充卡模式的一個特例,預設适配模式在java語言中有着特殊的應用.(引用java模式書)

adapter是一個非常常用的設計模式.

像windows的每個視窗,事件很多個.關閉,移動,最大化,最小化,

java代碼設計如下:

interface 視窗{

public void 關閉();

public void 移動();

public ovid 最大化();

...

}

如果客戶點選了關閉按鈕,java類實作如下:

Frame implements 視窗{

public void 關閉(){

System.out.println("關閉視窗");

public void 移動()[

public ovid 最大化(){

這裡面我們可以看出,我們關注的隻有關閉按鈕觸發的事件,其它的我們不用管.但是在java類中,我們必須把接口的所有方法都給實作.這樣我們連一些沒有用的方法也得給實作.那怕是空實作.

下面我們來建一個抽象類來實作這個接口.

public abstract Frame implements 視窗{

public void 移動(){

這裡我們可以看出,抽象類給每個接口一個空的實作,那我們都可以在抽象類的基礎上進行擴充。關閉功能實作如下:

public CloseFrame extends Frame{

像在java中的事件處理都是用擴充卡模式來實作的。接口,抽象類都是已經寫好的。我們隻需要實作具體功能的類就可以了。

再舉個簡單的例子:

假如存在如下接口:

interface TestInterface{

void test1();

void test2();

void test3();

如果我們隻關注test1接口應該怎樣寫呢。

abstract class TestAbstract implements Test{

public void test1(){

public void test2(){

public void test3(){

class TestTest1 extends TestAbstract{

System.out.println("方法1實作");

那麼在什麼情況下用相信大家已經能看得出來了吧。假如你不準備實作接口的所有方法。就可以建一個抽象類來實作這個接口的所有方法,當然這裡全都是空的實作.然後再寫一個類繼承這個抽象類就可以得到你想要的結果了.

一個更簡單的例子

一般都是抽象類,API中很多都是這樣的.比如在API中有

java.awt.event.WindowListener接口這樣定義的:(接口聲明了很多對視窗的事件)

public interface WindowListener{

public void windowActivated(WindowEvent e) {

public void windowClosed(WindowEvent e) {

public void windowClosing(WindowEvent e) {

public void windowDeactivated(WindowEvent e) {

public void windowDeiconified(WindowEvent e) {

public void windowIconified(WindowEvent e) {

public void windowOpened(WindowEvent e) {

但 是如果需要做一個關閉window的操作,如果直接實作這個接口的話,那麼你必須對它聲明的是以方法都實作,顯然在邏輯中除了windowClosed(WindowEvente)方法外,對其他方法的實作都是做多餘的操作.這樣就出現了windowListener擴充卡類: 

  public abstract class WindowAdapter

  implements WindowListener

  {

  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 windowDeactivated(WindowEvent e){}

  }

顯然他是一個抽象類,之是對WindowListener的一個簡單的實作而已,是以的方法都隻做了空實作[沒有方法體].而他的好處是:如果你隻需要關閉視窗這一事件,則可以讓處理類繼承WindowAdapter這個抽象類,重寫他的windowClosing(WindowEvente)方法就是了.

WindowListener close = new WindowAdapter(

public void windowClosing(WindowEvent e){

System.exit(0);

);

這樣比實作接口就輕松多了啊,把它整成抽象類,是因為他的方法都是空實作,顯然拿到他的執行個體也沒有用的