Java 设计模式 接口型模式 之 适配器Adapter模式 (二)

适配器模式的意图 : 使用不同接口的类所提供的服务为客户端提供其所希望的接口;

-- 问题解决场景 : 在 类A 中实现了接口中的抽象方法, 客户端B 已经定义好了方法的调用, 但是调用的方法 与 类A 中的方法名不同, 这时我们就需要适配器模式了;

-- eg : 类A 实现了接口A1, 类B 实现了接口B1, 这里C调用 A 和 B 希望 A 和 B 能提供相同方法的接口, 这时我们需要使用适配器模式;

1. 接口适配

(1) 接口适配简介

接口适配 : 

-- 问题场景 : 客户端需要调用 客户端类接口 中提供的 requiredMethod()的方法, 但是工具类中只提供了一个 existMethod() 方法, 显然客户端接口 与 工具类中提供的方法名称不匹配;

-- 适配方案 :  创建一个 适配器类, 适配现有的代码 工具类,  该类实现客户端接口的 requiredMethod()抽象方法,
与客户端接口是实现关系, 同时该实现类继承 工具类, 可以调用工具类中的方法, 与工具类的关系是 继承关系;

-- 方法委托 : 通过接口适配, 就将 客户端类的requiredMethod() 方法 委派给了 existMethod()方法;

(2) 接口适配实例

.

接口适配需求 : 

-- 客户端提供接口 : 需要研发一种M1坦克, 需要实现接口 getCaliber() 获取火炮口径, fire() 开火, run()移动 等方法; 

-- 现有接口 : 现有的坦克 有 getGunCaliber() 获取火炮口径, GunFire() 火炮开火, Move() 移动 等方法;

-- 适配要求 : 写一个适配类, 这个类实现 Panzer 接口继承 Tanker 类,
将Panzer接口的动作委托给 Tanker 类;

接口类 : 

[java] view
plain
copy

  1. package shuliang.han.displaytest;  
  2.   
  3. public interface Panzer {  
  4.   
  5.     public double getCaliber();  
  6.     public void fire();  
  7.     public void run();  
  8.       
  9. }  

实体类 : 

[java] view
plain
copy

  1. package shuliang.han.displaytest;  
  2.   
  3.   
  4. public class Tanker {  
  5.   
  6.     private double caliber = 125.0;  
  7.       
  8.     public double getGunCaliber() {  
  9.         return caliber;  
  10.     }  
  11.       
  12.     public void gunFire() {  
  13.         System.out.println("Fire in the hole !!!");  
  14.     }  
  15.       
  16.     public void move() {  
  17.         System.out.println("Move move !!");  
  18.     }  
  19.       
  20. }  

分析 : 

-- 名称不匹配 : Tanker类中的方法可以执行 Panzer 接口中需要的动作, 但是它们的方法名称不匹配;

-- 变量维护 : 如果创建一个 M1A2SEP 类, 需要在类中维护一个 Tank 对象, 在 Panzer 实现类中调用 对应的 Tank 对象方法;

M1A2SEP 类 : 

[java] view
plain
copy

  1. package shuliang.han.displaytest;  
  2.   
  3. public class M1A2SEP extends Tanker implements Panzer  {  
  4.   
  5.     @Override  
  6.     public double getCaliber() {  
  7.         return getGunCaliber();  
  8.     }  
  9.   
  10.     @Override  
  11.     public void fire() {  
  12.         gunFire();  
  13.     }  
  14.   
  15.     @Override  
  16.     public void run() {  
  17.         move();  
  18.     }  
  19.   
  20. }  

接口适配总结 : 

-- 客户端接口存在 : 如果客户端接口中定义了客户端所期待的行为, 可以运用适配器模式, 适配器继承现有类, 并实现客户端接口;

-- 客户端接口不存在 : 如果客户端没有定义接口, 可以使用对象适配器, 对象适配器相当于 子类适配器;

2. 对象适配

(1) 对象适配简介

类适配 : 上面的接口适配方式就是类适配, 适配器类需要 实现客户端接口继承 现有实体类;

对象适配 : 对象适配器采用了委派, 并非是继承; 创建一个对象适配器, 继承客户端类,
在类中维护一个现有类实例对象, 满足客户端类需求方法; 

-- 需要场景 : 如果适配的客户端方法没有被定义在接口中, 就需要对象适配;

对象适配的方法 : 

-- 适配器类继承客户端类 : 对象适配的适配器类 继承客户端类对象, 适配器类 的 实例 也是 客户端类的实例, 因为适配器类是客户端类的子类;  

-- 适配器类使用现有类 : 适配器类中定义一个 现有类对象作为成员变量, 通过调用 现有类对象中的方法 来实现客户端类方法的需求;

(2) 对象适配实例

客户端类 : 现在有客户端类 Panzer 装甲车, 提供 获取火炮口径方法 getCaliber(), 移动方法 run(), 开火方法 fire(); 

现有类 : 现有类 Tank 坦克, 提供 获取火炮口径方法 getGunCaliber(), 移动方法 move(), 开火方法 gunFire();

客户端类代码 : 客户端类代码中没有指定建模所需的接口;

[java] view
plain
copy

  1. package shuliang.han.adapter;  
  2.   
  3. public class Panzer {  
  4.   
  5.     public double getCaliber(){  
  6.         return 0;  
  7.     }  
  8.       
  9.     public void fire(){  
  10.         //TODO  
  11.     }  
  12.       
  13.     public void run(){  
  14.         //TODO  
  15.     }  
  16. }  

现有类代码 : 

[java] view
plain
copy

  1. package shuliang.han.adapter;  
  2.   
  3. public class Tank {  
  4.   
  5.     private double caliber = 125.0;  
  6.       
  7.     public double getGunCaliber(){  
  8.         return caliber;  
  9.     }  
  10.       
  11.     public void gunFire() {  
  12.         System.out.println("Fire in the hole !!!");  
  13.     }  
  14.       
  15.     public void move() {  
  16.         System.out.println("Move Move !!!");  
  17.     }  
  18. }  

UML图 

适配器类 

[java] view
plain
copy

  1. package shuliang.han.adapter;  
  2.   
  3. public class M1A2 extends Panzer {  
  4.       
  5.     private Tank tank;  
  6.       
  7.     public M1A2() {  
  8.         tank = new Tank();  
  9.     }  
  10.       
  11.     @Override  
  12.     public double getCaliber() {  
  13.         return tank.getGunCaliber();  
  14.     }  
  15.   
  16.     @Override  
  17.     public void fire() {  
  18.         super.fire();  
  19.         tank.gunFire();  
  20.     }  
  21.       
  22.     @Override  
  23.     public void run() {  
  24.         super.run();  
  25.         tank.move();  
  26.     }  
  27.       
  28. }  

(3) 脆弱的对象适配

对象适配比类适配要脆弱 : 

-- 没有规范接口 : 对象适配的类中没有规范的接口, 如果客户端类出现了变化,
运行时可能出现错误;

-- 客户端类不可预知 : 对象适配类 继承客户端类, 首先客户端类需要将方法 和 变量声明为 protected, 即使这样, 这些类的方法也可能不符合子类意图;

3. Jtable 对数据适配

(1) Jtable 与 TableModel AbstractTableModel模型 

JTable适配数据方法 : JTable类可以将实现了TableModel抽象类的数据显示到图形界面中;

-- 数据不确定性 : Java中的Swing 提供了JTable控件用以显示列表, JTable不知道我们要显示什么数据

-- 适配器 : 将数据交给JTable控件并显示出来, 需要一个适配器, 这些数据要经过一个适配器接口, 这个接口是 TableModel 抽象类;

TableModel子类实现 

-- 抽象方法多 : Jtable定义了许多抽象方法, 其子类必须实现所有的抽象方法, 这样会很麻烦; 

-- TableModel的桩 : JDK中提供了另一个抽象类 AbstractTableModel 类, AbstractTableModel 继承了 TableModel 类, 并实现了绝大部分方法,
我们可以定义一个类 去 继承 AbstractTableModel 类, 并实现我们感兴趣的方法, 不必实现所有的方法了;

-- 数据封装 : 创建一个类 继承 AbstractTableModel 类, 然后呢实现感兴趣的接口;

(2) 实例

实现过程 : 使用JTable 绘制坦克相关数据, 需要创建一个TankTableModel类 继承 AbstractTableModel 类, 然后将 Tank 类封装在 TankTableModel
中, 当做其成员变量;

使用对象适配的原因 : 

-- AbstractTableModel 抽象类 : 该抽象类提供了适配器对象需要实现的接口 (抽象方法), 该抽象类又实现了客户端 JTable类 期待的接口,
适配器对象必须继承抽象类;

-- 组合第三对象 : 适配器对象还需要重用第三个对象, 重用对象的方法只能是
继承 和 组合, Java是单继承机制, 只能使用组合方式, 即将第三个对象当做适配器类的成员变量;

UML图 : 

Tank代码 

[java] view
plain
copy

  1. package shuliang.han.jtable;  
  2.   
  3. public class Tank {  
  4.   
  5.     private double caliber;  
  6.     private double speed;  
  7.     private String name;  
  8.       
  9.     public Tank(double caliber, double speed, String name) {  
  10.         this.caliber = caliber;  
  11.         this.speed = speed;  
  12.         this.name = name;  
  13.     }  
  14.   
  15.     public double getCaliber() {  
  16.         return caliber;  
  17.     }  
  18.   
  19.     public double getSpeed() {  
  20.         return speed;  
  21.     }  
  22.   
  23.     public String getName() {  
  24.         return name;  
  25.     }  
  26.       
  27.       
  28. }  

TankTableModel代码 : 

[java] view
plain
copy

  1. package shuliang.han.jtable;  
  2.   
  3. import javax.swing.table.AbstractTableModel;  
  4.   
  5. public class TankTableModel extends AbstractTableModel {  
  6.   
  7.     private Tank tanks[];  
  8.     private String names[];  
  9.       
  10.     public TankTableModel(Tank[] tanks, String[] names) {  
  11.         this.tanks = tanks;  
  12.         this.names = names;  
  13.     }  
  14.       
  15.     @Override  
  16.     public int getRowCount() {  
  17.         return tanks.length;  
  18.     }  
  19.   
  20.     @Override  
  21.     public int getColumnCount() {  
  22.         return names.length;  
  23.     }  
  24.   
  25.     @Override  
  26.     public String getColumnName(int column) {  
  27.         return names[column];  
  28.     }  
  29.       
  30.     @Override  
  31.     public Object getValueAt(int rowIndex, int columnIndex) {  
  32.         switch(columnIndex){  
  33.             case 0 :  
  34.                 return tanks[rowIndex].getName();  
  35.             case 1 :  
  36.                 return new Double(tanks[rowIndex].getCaliber());  
  37.             case 2 :  
  38.                 return new Double(tanks[rowIndex].getSpeed());  
  39.             default :  
  40.                 return null;  
  41.         }  
  42.     }  
  43.   
  44. }  

ShowTankData代码 : 

[java] view
plain
copy

  1. package shuliang.han.jtable;  
  2.   
  3. import java.awt.Component;  
  4. import java.awt.Dimension;  
  5. import java.awt.Font;  
  6.   
  7. import javax.swing.JFrame;  
  8. import javax.swing.JScrollPane;  
  9. import javax.swing.JTable;  
  10. import javax.swing.UIManager;  
  11.   
  12. public class ShowTanksData {  
  13.   
  14.     public static void main(String[] args) {  
  15.         setFrame();  
  16.         JTable jTable = new JTable(getTankTableModel());  
  17.         jTable.setRowHeight(36);  
  18.         JScrollPane pane = new JScrollPane(jTable);  
  19.         pane.setPreferredSize(new Dimension(300, 100));  
  20.         display(pane, "坦克数据");  
  21.     }  
  22.       
  23.     private static void setFrame() {  
  24.         Font font = new Font("Dialog", Font.PLAIN, 18);  
  25.         UIManager.put("Table.font", font);  
  26.         UIManager.put("TableHeader.font", font);  
  27.     }  
  28.       
  29.     private static TankTableModel getTankTableModel() {  
  30.         Tank tank1 = new Tank(120.0, 50.0, "99式");  
  31.         Tank tank2 = new Tank(150.0, 2.0, "KV");  
  32.         return new TankTableModel(new Tank[]{tank1, tank2}, new String[]{"名称", "火炮口径 ", "速度"});  
  33.     }  
  34.       
  35.     private static void display(Component component, String tittle) {  
  36.         JFrame frame = new JFrame(tittle);  
  37.         frame.getContentPane().add(component);  
  38.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  39.         frame.pack();  
  40.         frame.setVisible(true);  
  41.     }  
  42.   
  43. }  

效果图 : 

4. 识别适配器

MouseAdapter 为 MouseListener 接口提供桩的实现;

在使用MouseAdapter的时候, 就相当于使用了适配器 : 用户操作鼠标的时候, 将swing组件接收到的鼠标操作适配给相应的动作处理类中,
即将GUI时间适配给应用程序接口, 使用了Swing适配类, 将一个接口方法委派给一个类的方法去执行;

5. 适配器模式总结

适配器总结 : 适配器模式可以重用一个现有类, 满足客户端需求, 将客户端的调用转化为现有方法的调用;

-- 类适配器 : 客户端的需求通过接口表达出来, 可以创建一个实现了该接口的适配类, 适配类同时还要继承现有类;

-- 对象适配 : 客户端没有指定接口, 创建一个新适配器类, 实现 继承客户端类, 在该类中维护一个现有类的实例对象作为成员变量;

JTable适配器模式 : 通过定义TableModel接口, JTable组件将客户端需要的表信息存储到自身中, 通过自定义适配器对象, 将任何数据适配到表中;

JTable不适用类适配原因 : 

-- 继承数量限制 : JTable适配器需要继承 AbstractTableModel类, 这样就无法继承现有类, 因为只能继承一个类;

-- 需要维护多个对象 : JTable需要大量数据, 一般是从多个对象中采集的;

设计适配器模式 : 当我们设计软件的时候, 充分考虑程序的灵活性, JTable 的设计就是一个很好的范例;

时间: 2024-11-08 17:29:06

Java 设计模式 接口型模式 之 适配器Adapter模式 (二)的相关文章

Java 设计模式 接口型模式 之 类型介绍 (一)

接口型模式组成 : 该模式包括适配器(Adapter)模式,外观(Facade)模式,合成(Composite)模式,桥接(Bridge)模式 四种模式; 类的接口 :  -- 前置条件 : 接口A, 类B, 类B实现接口A;  -- 允许访问 : 类A允许其它类的对象可以访问类B的 方法 与 字段, 类A 是类B的接口;  -- 实现关系 : 类B 方法需要实现 类A接口的方法名表示的操作, 类A 的实现就是 类B 中方法体的代码;  接口与实现的概念 : 接口 与 实现 二者是分离的, Ja

Android设计模式之适配器(Adapter)模式_Android

本文实例为大家分享了Android适配器模式源码,供大家参考,具体内容如下 1. 模式介绍 1.1模式的定义: 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 1.2模式的使用场景: 用电源接口做例子,笔记本电脑的电源一般都是接受5V的电压,但是我们生活中的电线电压一般都是220V的输出.这个时候就出现了不匹配的状况,在软件开发中我们称之为接口不兼容,此时就需要适配器来进行一个接口转换.在软件开发中有一句话正好体现了这点:任

Android设计模式之适配器(Adapter)模式

本文实例为大家分享了Android适配器模式源码,供大家参考,具体内容如下 1. 模式介绍 1.1模式的定义: 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 1.2模式的使用场景: 用电源接口做例子,笔记本电脑的电源一般都是接受5V的电压,但是我们生活中的电线电压一般都是220V的输出.这个时候就出现了不匹配的状况,在软件开发中我们称之为接口不兼容,此时就需要适配器来进行一个接口转换.在软件开发中有一句话正好体现了这点:任

【java设计模式】之 工厂(Factory)模式

版权声明:尊重博主原创文章,转载请注明出处哦~http://blog.csdn.net/eson_15/article/details/51223124 目录(?)[+] 1.工厂模式的定义         工厂模式使用的频率非常高,我们在开发中总能见到它们的身影.其定义为:Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method

【java设计模式】之 建造者(Builder)模式

版权声明:尊重博主原创文章,转载请注明出处哦~http://blog.csdn.net/eson_15/article/details/51325765 目录(?)[+]         我们还是举上一节的例子:生产汽车.上一节我们通过模板方法模式控制汽车跑起来的动作,那么需求是无止境的,现在如果老板又增加了额外的需求:汽车启动.停止.鸣笛引擎声都由客户自己控制,他想要什么顺序就什么顺序,那该如何做呢? 1. 汽车无休止的改造         假如现在要生产两种车,奔驰和宝马,这两辆车都有共性,

详解Java设计模式编程中的Flyweight享元模式的开发结构_java

享元(Flyweight)模式:通过共享技术以便有效的支持大量细粒度的对象. 享元模式在阎宏的<java与模式>中分为单纯享元模式和复合享元模式,复合模式的复合享元是不可以共享的,享元对象能做到共享的关键是区分内蕴态(Internal State)和外蕴态( External State).这两个"蕴态"翻译的太难懂,我不是说翻译的不好,可能是我理解能力差,还是<Design Pattern Elements of Reusable Object-Oriented S

Adapter(适配器)模式

1. 概述:          接口的改变,是一个需要程序员们必须(虽然很不情愿)接受和处理的普遍问题.程序提供者们修改他们的代码;系统库被修正;各种程序语言以及相关库的发展和进化.         例子1:iphone4,你即可以使用UBS接口连接电脑来充电,假如只有iphone没有电脑,怎么办呢?苹果提供了iphone电源适配器.可以使用这个电源适配器充电.这个iphone的电源适配器就是类似我们说的适配器模式.(电源适配器就是把电源变成需要的电压,也就是适配器的作用是使得一个东西适合另外一

亲身实践,JAVA最优良的Adapter模式--适配器模式

网上关于JAVA的适配器模式例子有很多,但真的有少实在不怎么样,看也不懂.自己总结了一个在性能和结构上都很容易理解的Adapter模式. Adapter模式也叫适配器模式,是由GoF提出的23种设计模式的一种.Adapter模式是构造型模式之一,通过Adapter模式,可以改变已有类(或外部类)的接口形式. 在大规模的系统开发过程中,我们常常碰到诸如以下这些情况: 我们需要实现某些功能,这些功能已有还不太成熟的一个或多个外部组件,如果我们自己重新开发这些功能会花费大量时间:所以很多情况下会选择先

Java最优良的Adapter模式:适配器模式

网上关于JAVA的适配器模式例子有很多,但真的有少实在不怎么样,看也不懂.自己总结了一个在性能和结构上都很容易理解的Adapter模式. Adapter模式也叫适配器模式,是由GoF提出的23种设计模式的一种.Adapter模式是构造型模式之一,通过Adapter模式,可以改变已有类(或外部类)的接口形式. 在大规模的系统开发过程中,我们常常碰到诸如以下这些情况: 我们需要实现某些功能,这些功能已有还不太成熟的一个或多个外部组件,如果我们自己重新开发这些功能会花费大量时间:所以很多情况下会选择先