现在的位置: 首页 > 综合 > 正文

详解 JAVA 适配模式 和 接口适配器

2018年04月02日 ⁄ 综合 ⁄ 共 4421字 ⁄ 字号 评论关闭

JAVA适配模式

意图
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。(GoF)

场景
相信很多人都知道什么是显卡,也有很多人知道显卡的本名——图形适配器。恩,是的,正好这回说说Apater模式,就拿显卡来例子来分析一下Adapter模式。

我们知道显示器(Client)是用来显示图形的,它是不能显示数据,它只能够接受来自图形发送设备Target的信号。可是我们手头上只有CPU(Adaptee)这个产生各种描述图形的数据的数据发送器。我们需要将这些数据让显示器进行显示,可是这两个部件却是不兼容的。于是我们需要一个中间设备,它能够将CPU“适配”于显示器,这便是我们的显卡——图形适配器(Adapter)。

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)。

java 代码

    //CPU 
    public classAdaptee { 
        
       public String getData() { 
           return "CPU data"; 
       } 
   } 

这个时候我们的显卡(Adapter)的作用便体现出来了,它负责对CPU进行适配,通过将CPU传过来的数据转换成图形信号,从而将CPU伪装成一个图形发送设备。

java 代码

 

   //显卡,即我们的适配器 
    public classAdapter extends Target { 
     
       // 被代理的设备 
       private Adaptee apt = null; 
     
        
       public Adapter(Adaptee apt) { 
           this.apt = apt; 
       } 
     
        
       public String request() { 
           return apt.getData(); 
       } 
   } 

这样,我们的电脑的显示流程就变成CPU-显卡-显示器:

java 代码

   

 public class Client { 
     
       public static void main(String[] args) { 
           // CPU经过显卡的适配后“变”成了图形发送装置了 
           Target target = new Adapter(new Adaptee()); 
           System.out.println(target.request()); 
       } 
         
   } 

上面的这种依赖于对象组合的Adapter模式叫做对象适配器(ObjectAdapter)。它的特征是继承/实现某一方的类(Target),如这里的图形发送器,同时内部包含一个被适配的类(Adaptee),如这里的CPU。通过重写其父类的方法来进行适配。

另一种的Adapter实现
对于Adapter模式,还有另外一种实现方式,这种适配方式叫做类适配器(ClassAdapter)。它与Object Adapter的不同之处在于它继承被适配的对象。

java 代码
    public classAdapter extends Targer, Adaptee { 
       ...... 
   } 

这样的代码在C++中是合法的,但是在Java中规定最多只能继承一个父类,而可以实现多个接口。所以我们需要建立一个IAdaptee的接口,然后将我们的Adapter继承Target同时实现IAdaptee。

java 代码
 

 

   //IAdaptee接口 
    publicinterface IAdaptee{   
       String getData(); 
   }  


java 代码
 

    // Adaptee实现IAdaptee
    public classAdaptee implements IAdaptee { 
     ...... 
   }   


java 代码
 

    public classAdapter extends Target implements IAdaptee{ 
     
       private IAdaptee apt = null; 
     
       public Adapter(IAdaptee apt) { 
           this.apt = apt; 
       } 
     
       public String request() { 
           return apt.getData(); 
       } 
     
       public String getData() { 
           return apt.getData(); 
       } 
   } 

对于我们的显示器(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 void 移动(){
}
public ovid 最大化(){
}
...
...
}
这里我们可以看出,抽象类给每个接口一个空的实现,那我们都可以在抽象类的基础上进行扩展。关闭功能实现如下:
public CloseFrame extends Frame{
public void 关闭(){
System.out.println("关闭窗口");

}
}

像在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{
public void test1(){
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);
}
);
这样比实现接口就轻松多了啊,把它整成抽象类,是因为他的方法都是空实现,显然拿到他的实例也没有用的

抱歉!评论已关闭.