Adapter(适配器)模式

适配器模式保留现有类所提供的服务,向客户提供接口,以满足客户的期望。适配器模式可分为类适配器模式、对象适配器模式和标识适配器模式三种。

类适配器模式

拓展一个现有的类,并实现一个目标接口,将把客户的调用转变为调用现有类的方法。

对象适配器模式

拓展一个目标类,并把它委派给一个现有的类,将客户调用转发给现有类的实例。

  • 如果希望适配的方法没有在接口中指定时,就应该使用委托方式,而不是创建子类方式。即对象适配器模式。
  • 只要我们所适配的接口可以得到抽象类的支持,也必须使用对象适配器模式。
  • 如果适配器类需要从多个对象中提取信息,也应当使用对象适配器。

Swing中的JTable组件是应用对象适配器模式的很好例子。JTable组件通过调用TableModel接口中定义的方法获取表格

的相关信息,这样就可以很容易地写出一个适配器类,从域对象中获取用于填充表格的数据。

import javax.swing.table.*;
/**
 * Adapt a collection of rockets for display in a JTable.
 *
 * @author Steven J. Metsker
 */
public class RocketTableModel extends AbstractTableModel {
    protected Rocket[] rockets;
    protected String[] columnNames = new String[] { "Name", "Price", "Apogee" };

    /**
     * Construct a rocket table from an array of rockets.
     *
     * @param rockets
     *            an array of rockets
     */
    public RocketTableModel(Rocket[] rockets) {
        this.rockets = rockets;
    }

    /**
     * @return the number of columns in this table.
     */
    public int getColumnCount() {
        return columnNames.length;
    }

    /**
     * @param index
     *            which column is interesting
     * @return the name of the indicated column
     */
    public String getColumnName(int i) {
        return columnNames[i];
    }

    /**
     * @return the number of rows in this table.
     */
    public int getRowCount() {
        return rockets.length;
    }

    /**
     * @param row
     *            which row is interesting
     * @param col
     *            which column is interesting
     * @return the value at the indicated row and column.
     */
    public Object getValueAt(int row, int col) {
        switch (col) {
        case 0:
            return rockets[row].getName();
        case 1:
            return rockets[row].getPrice();
        case 2:
            return new Double(rockets[row].getApogee());
        default:
            return null;
        }
    }
}
import java.awt.Component;
import java.awt.Font;

import javax.swing.*;
public class ShowRocketTable {
    public static void main(String[] args) {
        setFonts();
        JTable table = new JTable(getRocketTable());
        table.setRowHeight(36);
        JScrollPane pane = new JScrollPane(table);
        pane.setPreferredSize(new java.awt.Dimension(300, 100));
        display(pane, " Rockets");
    }
    public static void display(Component c, String title) {
        JFrame frame = new JFrame(title);
        frame.getContentPane().add(c);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    private static RocketTableModel getRocketTable() {
        Rocket r1 = new Rocket("Shooter", 1.0, new Dollars(3.95), 50.0, 4.5);
        Rocket r2 = new Rocket("Orbit", 2.0, new Dollars(29.03), 5000, 3.2);
        return new RocketTableModel(new Rocket[] { r1, r2 });
    }

    private static void setFonts() {
        Font font = new Font("Dialog", Font.PLAIN, 18);
        UIManager.put("Table.font", font);
        UIManager.put("TableHeader.font", font);
    }
}
public class Dollars {
    public static final Dollars cent = new Dollars(0.01);

    static final int CENTS_PER_DOLLAR = 100;

    long cents;

    public Dollars(double value) {
        this.cents = Math.round(value * CENTS_PER_DOLLAR);
    }

    public boolean isZero() {
        return cents == 0;
    }

    public Dollars plus(Dollars that) {
        return new Dollars(1.0 * (this.cents + that.cents) / CENTS_PER_DOLLAR);
    }

    public Dollars times(int multiplier) {
        return new Dollars((this.cents * multiplier) / CENTS_PER_DOLLAR);
    }

    public Dollars dividedBy(int divisor) {
        double newCents = (1.0 * cents / divisor) / CENTS_PER_DOLLAR;
        return new Dollars(newCents);
    }

    public double dividedBy(Dollars that) {
        return (1.0 * this.cents) / that.cents;
    }

    public boolean isLessThan(Dollars that) {
        return this.cents < that.cents;
    }

    public String toString() {
        StringBuffer result = new StringBuffer("$");

        long dollars = cents / CENTS_PER_DOLLAR;
        result.append(dollars);
        result.append(‘.‘);

        long pennies = cents % CENTS_PER_DOLLAR;
        if (pennies < 10) result.append(‘0‘);
        result.append(pennies);

        return result.toString();
    }

    public boolean equals(Object obj) {
        if (!obj.getClass().equals(this.getClass()))
            return false;
        Dollars that = (Dollars) obj;
        return this.cents == that.cents;
    }

    public int hashCode() {
        return (int) cents;
    }

    public long asCents() {
        return cents;
    }
}
public class Rocket extends Firework {
    private double apogee;

    private double thrust;

    /**
     * Allow creation of empty objects to support reconstruction from persistent
     * store.
     */
    public Rocket() {
    }

    /**
     * Create a rocket with all its expected properties. See the superclass for
     * descriptions of other parameters
     *
     * @param apogee
     *            The height (in meters) that the rocket is expected to reach
     * @param thrust
     *            The rated thrust (or force, in newtons) of this rocket
     */
    public Rocket(String name, double mass, Dollars price, double apogee,
            double thrust) {
        super(name, mass, price);
        setApogee(apogee);
        setThrust(thrust);
    }

    /**
     * The height (in meters) that the rocket is expected to reach.
     */
    public double getApogee() {
        return apogee;
    }

    public void setApogee(double value) {
        apogee = value;
    }

    /**
     * The rated thrust (or force, in newtons) of this rocket.
     */
    public double getThrust() {
        return thrust;
    }

    public void setThrust(double value) {
        thrust = value;
    }
}
public class Firework {
    /**
     * @return a firework of the given name. This method supports a "Strategy"
     *         example, but it isn‘t really implemented.
     * @param name
     *            a name to lookup
     */
    public static Firework lookup(String name) {
        return new Firework(name, 9.0, new Dollars(3));
    }

    /**
     * @return a random firework from our shelves. This method is not actually
     *         implemented -- it‘s here as part of a "Strategy" example.
     */
    public static Firework getRandom() {
        return new Firework("Random firework", 10.0, new Dollars(15));
    }

    private String name;
    private double mass;
    private Dollars price;

    /**
     * Allow creation of empty objects to support reconstruction from persistent
     * store.
     */
    public Firework() {
    }
    public Firework(String name, double mass, Dollars price) {
        setName(name);
        setMass(mass);
        setPrice(price);
    }

    /**
     * The unique name of this type of firework
     */
    public String getName() {
        return name;
    }

    public void setName(String value) {
        name = value;
    }

    /**
     * The mass, in kilograms, of one instance of this type
     */
    public double getMass() {
        return mass;
    }

    public void setMass(double value) {
        mass = value;
    }

    /**
     * The price (in dollars) of one instance of this type
     */
    public Dollars getPrice() {
        return price;
    }

    public void setPrice(Dollars value) {
        price = value;
    }

    /**
     * @return a textual representation of this firework.
     */
    public String toString() {
        return getName();
    }
}

JTable类有两个原因不能使用类适配器:

  1. 表适配器必须拓展现AbstractTableModel类,应此它不能再拓展现有的类;
  2. JTable类需要收集多个对象的数据,只有对象适配器才可以对多个对象进行适配。

标识适配器模式

创建存根类MouseAdapter以后,在实现鼠标监听器类的时候,就不用实现MouseAdapter接口的所有方法

时间: 2024-10-29 19:11:35

Adapter(适配器)模式的相关文章

设计模式的征途—7.适配器(Adapter)模式

在现实生活中,我们的笔记本电脑的工作电压大多数都是20V,而我国的家庭用电是220V,如何让20V的笔记本电脑能够工作在220V的电压下工作?答案:引入一个电源适配器,俗称变压器,有了这个电源适配器,生活用电和笔记本电脑即可兼容. 在软件开发中,有时候也会存在这种不兼容的情况,我们也可以像电源适配器一样引入一个称之为适配器的角色来协调这些存在不兼容的结构,这种设计方案即称之为适配器模式. 适配器模式(Builder) 学习难度:★★☆☆☆ 使用频率:★★★★☆ 一.木有源码的算法库 Backgr

设计模式——适配器(Adapter)模式

概述 什么是适配器?在我们生活中的适配器比如插头转换器(中标转美标).USB接口转换器(type-c转苹果),电脑电源适配器(交流电转低电压直流)等.像这种将两者有差异的东西通过适配器使他们成为相互适合的东西.在程序世界中,经常存在现有的程序无法直接使用,需要做适当的变换后才能使用的情况,这种用于填补“现有程序”和“所需程序”之间差异的设计模式就是适配器(Adapter)模式.适配器模式有类适配器模式和对象适配器模式两种,前者使用继承,后者使用组合,所以后者比较灵活,推荐使用.下面通过实例对这两

设计模式之适配器模式 adapter 适配器模式分类概念角色详解 类适配器 对象适配器 接口适配器 双向适配器

现实世界中的适配器模型 先来看下来几个图片,截图自淘宝 上图为港版的插头与港版的插座 上图为插座适配器卖家的描述图 上图为适配后的结果 现实世界中适配器模式 角色分类 这就是适配器模式在电源插座上的应用 我们看下在插座适配器中的几个重要角色 可以看得出来,大陆和港版插座面板,都是作为电源的角色,他们的功能是相似的或者说相近的 插头要使用插座,进而接通电流 现实世界到代码的转换 电源插座代码示例 港版插座面板 package adapter; /**目标角色 Target 接口 * 香港地区使用的

Android adapter适配器的使用

ListView之SimpleAdapter SimpleAdapter的构造函数是: public SimpleAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) 参数context:上下文,比如this.关联SimpleAdapter运行的视图上下文 参数data:Map列表,列表要显示的数据,这部分需要自己实现,如例子中的ge

android学习笔记之ListView 和Adapter适配器

1.在学习Listview时候用到了Adapter适配器,定义MyAdapter时候需要继承ListAdapter接口,接口里很多方法没有实现,为了方便google工程师实现了个BaseAdapter类,我们在使用的时候可以继承这个抽象类,因此我们只需要完成几个抽象方法就可以了. public class Db_adapter extends BaseAdapter { private Context context; private List<Person> personlist; publ

七、适配器(Adapter)模式--结构模式(Structural Pattern)

适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作. 类的 Adapter模式的结构: 类适配器类图: 由图中可以看出,Adaptee 类没有 Request方法,而客户期待这个方法.为了使客户能够使用 Adaptee 类,提供一个中间环节,即类Adapter类, Adapter 类实现了 Target 接口,并继承 自 Adaptee,Adapter 类的 Request 方法重新封装了Adaptee 的SpecificRequ

Adapter(适配器)-类对象结构型模式

1.意图 将一个类接口转换成客户希望的另外一个接口.Adapter模式使那些原本不能一起工作的类,可以一起工作. 2.别名 包装器 Wrapper. 3.动机 一个应用可能会有一些类具有不同的接口,并且这些接口互不兼容,可以专门定义一个类,用来适配互不兼容的类. 4.适用性 你想使用一个已经存在的类,而它的接口不符合你的需求. 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作. 你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口.对象适配器可以适配

Java 适配器(Adapter)模式

一.什么是适配器模式: 把一个接口变成另外一个接口,使得原本因接口不匹配无法一起工作的两个类一起工作. 二.适配器模式的结构: (1)Target(目标抽象类):所期待的接口. (2)Adapter(适配器类):模式的核心类,作为转换器对Target和Adaptee进行适配. (3)Adaptee(适配者类):定义了需要适配的接口. (4)Client(客户类):针对目标抽象类编程,调用其定义的方法. 三.类适配器和对象适配器的比较: 类适配器中,适配器类通过实现Target接口并继承Adapt

JAVA设计模式(DESIGN PATTERNS IN JAVA)读书摘要 第1部分接口型模式——第3章 适配器(Adapter)模式

客户端代码提供接口来写具体实现类时,要利用已经实现接口功能的现有类,但是接口的方法名和现有类的方法名不一致,则需要使用适配器模式. 接口适配 如图所示, RequiredInterface接口声明了Client类所要调用的requiredMethod()方法,ExistingClass的usefulMethod()提供了此方法的具体实现,但是这两个方法的名字不同,这要对ExistingClass进行适配.适配类NewClass继承ExistingClass类,实现了RequiredInterfa