java desigin pattern -- adapter

本文详细介绍了Java中的适配器模式,包括DefaultAdapter、ObjectAdapter和ClassAdapter三种类型的应用场景与实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Adapter includes Default Adapter, Object Adapter, Class Adapter
 
Default Adapter:
 
在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 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) {}
}
 

然而这有个缺点,实作介面的原则是您必须实作当中所定义的所有方法,即使您对某些事件并不感兴趣,您也必须实作一个没有内容的空方法,代表您已经实作了介 面中定义的方法,然而有时,您并不知道介面中到底定义了几个方法,或是知道也不知道方法的确切名称与参数,即使您查了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) {}
}
 
可以继承WindowAdapter类别,并重新定义一些您所感兴趣的事件,如此一来,就可以避开之前所提及的,直接实作 WindowListener介面的缺点,如下所示:
public class WindowEventHandler extends WindowAdapter {
    public void windowClosed(WindowEvent e) {
        System.exit(0);
    }
}
 

这就是Default Adapter模式,它使用一个中介的Adapter类别来将真正感兴趣的事件实作类别,配接至事件处理介面,上面的程式其 UML 图如下:
DefaultAdapter

将上图一般化,Default Adapter模式的结构如下所示:
DefaultAdapter
 
Object Adapter:
 
您的电脑是个旧电脑,新的滑鼠都在使用USB接口了,而您的电脑上并没有USB,而只有一个PS2接口,这时您可以使用一个USB转PS2的接头作为转换,这样您的电脑就可以使用新滑鼠了(当然您也可以使用USB扩充卡,意思是相同的)。

类似的概念,有时候您想在原来的程式中加入一个外部元件,例如一个类别,但是这个类别与您目前所设计的程式在介面上并不一致,为了让这个外部类与原程式的介面一致,您必须使用一个类别作为中介来配接它们,这时您可以采用Adapter模式。

举个例子来说,在Java 1.0中有个Enumeration,您在这个版本发行之后,使用它来设计了一个MessageApplication,例如: 
  • MessageApplication.java
import java.util.*;

public class MessageApplication {
    public void showAllMessage(Enumeration enum) {
        Object msg;
        while(enum.hasMoreElements()) { 
            msg = enum.nextElement();
            System.out.println(msg);
        }
    }     
}

您的客户端程式是这么使用MessageApplication的:
  • MessageClient.java
import java.util.*;

public class MessageClient {
    private MessageApplication msgApp;

    public void run() {
        Vector vector = new Vector();
        for(int i = 0; i < 10; i++)
            vector.addElement("物件 " + i);
        
        msgApp = new MessageApplication();
        msgApp.showAllMessage(vector.elements());
    }
    
    public static void main(String[] args) {
        MessageClient msgClient = new MessageClient();
        msgClient.run();
    }
} 

现在Java 1.2中新增了Iterator,您想要使用它的功能,但基本上您不想更动原来程式中已设计好的MessageApplication类别,这时候您可以 使用Adapter模式,将Iterator的介面转换为Enumeration相容,例如:
  • IteratorAdapter.java
import java.util.*;

public class IteratorAdapter implements Enumeration {
    private Iterator iterator;

    IteratorAdapter(Iterator iterator) {
        this.iterator = iterator;   
    }

    // 转接介面
    public boolean hasMoreElements() {
        return iterator.hasNext();
    }

    public Object nextElement() 
                        throws NoSuchElementException {
        return iterator.next();
    } 
} 

您可以在客户端程式中照样使用MessageApplication类别,而不用作任何的变动:
  • MessageClient.java
import java.util.*;

public class MessageClient {
    // We could still use MessageApplication
    private Enumeration iteratorAdapter;
    
    public void run() {
        List arrayList = new ArrayList();

        for(int i = 0; i < 10; i++)
            arrayList.add("物件 " + i);
        
        iteratorAdapter = 
               new IteratorAdapter(arrayList.iterator());
        // We could still use MessageApplication
        MessageApplication msgApp = new MessageApplication();       
        msgApp.showAllMessage(iteratorAdapter);
    }

    public static void main(String[] args) {
        MessageClient msgClient = new MessageClient();
        msgClient.run();
    }
} 

如程式所示的,透过Adapter模式,您原有程式中已设计好的类别不用更动,就可以引进新类别的功能,将上面的程式UML类别结构画出如下:
Adapter

上面的作法,是将要引进的新类别当作Adapter类别的一个物件成员,这是IbObject Adapter模式,其抽象结构如下:
Adapter
Class Adapter:
 
Adapter模式的另一种作法是Class Adapter模式,在这个模式下,Adapter直接继承Adaptee(要引进的新类别),以拥有当中的成员及方法,在C++中的话可以这么作:
Adapter

C++中可以多重继承,但在Java中不行,所以在Java中若要采用Class Adapter,必须作点修改,一方面继承Adaptee,一方面实作Target的介面:
Adapter
代码的实现是这样的: 
public class Adapter extends Adaptee implements Target {
    // ....
}
当然,这必须您原先的Target定义了共同的介面,所以Class Adapter在Java中适用的场合较少,事实上,也比较建议使用Object Adapter,这样的Adapter模式比较有弹性,例如,您可以在Adapter上加上个setter,以随时可以抽换Adaptee。 在Java中,Class Adapter的一个应用场合是达到多重继承的效果,您一定在很多时候听别人说,介面(interface)可以达到多重继承的效果,这是怎么回事? 其实要讨论这个问题,首先您对于C++中多重继承要先有认识,新手看了书说介面可以达到多重继承,切莫人云亦云,尤其是没有学过C++的新手们,如果您对 于C++多重继承想要有所认识,请先看看  多 重继承(一)与  多 重继承(二)。 Java不能多重继承,但为何说Java中可以使用介面(interface)来达到多重继承的效果,首先效果之一,就如  多 重继承(二) 中描述的“ 多重继承时通常其中一个基底类别作为private实作体,而其它的用以表现完全的抽象介面。”,在Java中这个效果可以使用介面来达到,介面此时所扮 演的即  多 重继承(二) 中的抽象类别,一个完全的抽象介面,这个效果的达成方式,如  介 面(interface)型态 中所介绍的,您可以直接对应这两个主题中的程式实作来了解,了解Java中如何使用介面(interface)来达到C++中所谓多重继承的“一种”效 果。 来看看另一个情况。 如果有SomeClass类别与OtherClass类别,您想要SomeAndOther类别可以同时拥有SomeClass类别与 OtherClass类别中已定义好的操作,并可以进行多型操作,在C++中可以用多重继承来达到,但在Java中显然的无法使用多重继承,怎么办?您可 以在设计上先绕个弯,先使用两个介面分别定义好SomeClass与OtherClass两个类别的公开方法,例如:
public interface ISome {
    public void doSome();
}

public interface IOther {
    public void doOther();
}
接着让SomeClass与OtherClass分别实作两个介面:
public class SomeClass implements ISome {
    public void doSome() {
        ....
    }
}

public class OtherClass implements IOther {
    public void doOther() {
        ....
    }
}
SomeAndOther如何同时拥有两个SomeClass与OtherClass类别已定义好的操作?并可以多型操作?SomeAndOther可以 继承其中之一,并拥有其中之一,例如:
public class SomeAndOther extends SomeClass implements IOther {
    private IOther other = new OtherClass();

    public void doOther() {
        other.doOther();
    }
}
虽不满意,但至少解决了目前的问题,当然这边只是其中一例,毕竟C++是C++,Java是Java,两者语法并不是一对一的关系,视实际需求还可以变化 一下。

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值