经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
Java设计模式——适配器模式(Adapter)
来源:cnblogs  作者:Lurker潜行者  时间:2018/10/15 9:22:36  对本文有异议

目的:把源类型适配为目标类型,以适应客户端(Client)的需求;此处我们把目标接口的调用方视为客户端

使用场景:需要对类型进行由源类型到目标类型转换的场景中

前置条件已有客户端

  1. //Client 一个调用目标接口的方法Class ClientInvoking {static void invoke(TargetInterface target) {
  2.         String value = target.getMark();
  3.         System.out.println(value);
  4.     }
  5.  
  6. }

常用的几种模式

模式一:存在目标接口,且存在已有方法

  1. //目标接口public interface TargetInterface {    public String getMark();public String getInfo();
  2.  
  3. }
  1. //已有类及方法public class ExistClass {public String sayHello() {return "Hello";
  2.     }      public String sayWorld() {return "World";
  3.     }
  4. }

我们假设ExistClass返回的字符串正好是我们的客户端需要用到的,但客户端需要的是通过一个TargetInterface类型的对象来获取,因此我们需要想办法对已有类进行适配,使其能够满足客户端的需求;该模式下存在两种应用方案:

方案1.类适配器模式

  1. //适配器public class ClassAdapter extends ExistClass implements TargetInterface {    public int getMark() {
  2.         String value = this.sayHello();return value;
  3.     }    public int getInfo() {
  4.         String value = this.sayWorld();return value;
  5.     }
  6.     
  7. }
  1. //客户端调用TargetInterface target = new ClassAdapter();
  2. ClientInvoking.invoke(target);

由Java接口的概念可知,ClassAdapter作为TargetInterface的实现类,能够向上转型为TargetInterface类型,适应了客户端的需求。

方案2.对象适配器模式

  1. //适配器public class ClassAdapter implements TargetInterface {    private ExistClass exist;    public ClassAdapter(ExistClass existClass) {this.exist = existClass;
  2.     }    public int getMark() {
  3.         String value = exist.sayHello();return value;
  4.     }    public int getInfo() {
  5.         String value = exist.sayWorld();return value;
  6.     }
  7.     
  8. }
  1. //客户端调用TargetInterface target = new ClassAdapter(new ExistClass());
  2. ClientInvoking.invoke(target);

该方案与类适配器模式类似,只是不采用继承而采用持有对象的方式,更加灵活,扩展性更强。

模式二:不存在目标接口,但是存在目标类,且存在已有方法

我们先对前置条件中的客户端进行改造,如下:

  1. Class ClientInvoking {static void invoke(TargetClass target) {
  2.         String value = target.getMark();
  3.         System.out.println(value);
  4.     }
  5.  
  6. }

改造后,invoke方法需要一个TargetClass类的对象作为参数;下面是目标类和已有类

  1. //目标类public class Class {    public String getMark() {return "yes";
  2.     }public String getInfo() {return "no";
  3.     }
  4.  
  5. }
  1. //已有类及方法public class ExistClass {public String sayHello() {return "Hello";
  2.     }      public String sayWorld() {return "World";
  3.     }
  4. }

我们假设ExistClass返回的字符串正好是我们的客户端需要用到的,且客户端中需要的TargetClass对象的内容已经过时,因此我们需要相办法对ExistClass进行适配,以适应客户端的需求;

  1. //适配器public class ClassAdapter extends TargetClass {    private ExistClass exist;    public ClassAdapter(ExistClass existClass) {this.exist = existClass;
  2.     }    public int getMark() {
  3.         String value = exist.sayHello();return value;
  4.     }    public int getInfo() {
  5.         String value = exist.sayWorld();return value;
  6.     }
  7.     
  8. }
  1. //客户端调用TargetClass target = new ClassAdapter(new ExistClass());
  2. ClientInvoking.invoke(target);

在该种模式下,设计到两个类,且最后要进行向上转型,根据Java的单继承机制,我们只能通过持有对象的形式,即对象适配器模式。

模式三:缺省适配器模式

该模式中,不存在显式的目标类型,而仅有源类型;之所以需要用到这个,往往是因为源类型中提供了太多我们并不需要的东西,我们需要通过适配器模式进行定制化。以WindowListener作为例子讲解:

  1. //WindowListener源码public interface WindowListener extends EventListener {public void windowOpened(WindowEvent e);public void windowClosing(WindowEvent e);public void windowClosed(WindowEvent e);
  2.     ...
  3. }
  1. //添加监听器的例子Frame frame = new Frame();
  2. frame.addWindowListener(new WindowListener() {
  3.     @Overridepublic void windowOpened(WindowEvent e) {
  4.             
  5.     }
  6.  
  7.     @Overridepublic void windowClosing(WindowEvent e) {
  8.  
  9.     }
  10.  
  11.     @Overridepublic void windowClosed(WindowEvent e) {
  12.  
  13.     }
  14.     ...
  15. })

这样的代码,看起来很繁琐;比如说我只需要监听正在关闭的事件,却生成了许多与此无关的模板代码,降低了代码的可读性,鉴于此,我们来做下定制,只监听一个接口;

我们首先提供一个抽象类实现了该接口,并为所有监听器提供空实现;然后再用抽象类的子类重写窗口正在关闭的监听器的实现,代码如下:

  1. //适配器public abstract ListenerAdapter implements WindowListener {public void windowOpened(WindowEvent e) {}public void windowClosing(WindowEvent e) {}public void windowClosed(WindowEvent e) {}
  2.     ...
  3. }
  1. //重写方法public class OverrideWindowClosing extends ListenerAdapter {
  2.     
  3.     @Overridepublic void windowClosing(WindowEvent e) {//TODO    }
  4.     
  5. }
  1. //客户端调用frame.addWindowListener(new OverrideWindowClosing());

该方式简化了接口,提高了代码可读性。最重要的是,我们实现了对接口的定制,可以只做自己关心的事情。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号