【设计模式】之适配器模式

适配器模式

什么是适配器模式

  • 适配器模式属于结构型模式,可以使得两个不匹配的接口可以协同工作。
  • 适配器模式允许两个不匹配的类通过将其中一个接口类型转换成另一个客户端期望的接口类型,从而达到二者协同工作。
  • 适配器模式也叫包装器。
    适配器模式在 Gang of Four 书中原始的定义如下:

将一个类的接口类型转换成另一个客户端期望的接口类型。
适配器可以让多个类协同工作即使他们本来是不匹配的接口类型。

适配器模式的应用场景

  • 考虑一个这样的场景,你在印度购买了一个轻便的笔记本,最近你刚搬到英国。但是英国的电子插座和印度的不一样。因此,你的笔记本不能直接工作了。
    你必须去购买一个适配器,可以为你的印度笔记本可以在英国的插座上充电。

  • 当你有一个需要与新系统集成的遗留接口时,新系统不能直接接收遗留库的工作方式。由于遗留库不再进行开发了,所以我们需要使用适配器促使两种不同的类型进行工作。

  • 你使用 Mac 时,经常需要转接头才能连接到会议室的投影仪,这个转接头,就是适配器,使得原本 Mac 、投影仪互不相容的两个物件可以协同工作。

适配器模式的特点

  • 客户端通过使用目标接口调用适配器的方法向适配器发起请求。
  • 适配器通过适配器接口将请求转换成适配者的一个或多个调用。
  • 客户端收到调用结果,并且不感知存在一个适配器在做这个转换工作。

何时使用适配器模式

  • 如果你想要将已经存在的类和他们的接口类型去匹配你最后需要的接口类型,就可以使用适配器模式。
  • 如果你想创建可重用类以帮助在不匹配的两个类之间进行接口式交互。

适配器模式示例

劳埃德银行是一家提供全球性服务的国际性银行。境外账户持有人的税率为 0.03%。
在印度,它提供2种类型的账户,普通和白金。税法不适用于印度账户。
现在离岸账户就匹配不了印度账户了。
所以需要设计出一个账户适配器 AccountAdapter 促使2种不同的账户类型还可以继续一块工作。

这个示例的交互图如下所示。
在这里,客户端仅仅需要调用适配器的 getBalance() 方法。
适配器调用适配者的 getOffshoreBalance() 方法并返回客户端期望的结果。
适配器内部的 getBalance() 方法将会通过扣除税金来计算账户余额。

适配器模式时序图

Adapter-Design-Pattern-Sequence-Diagram-620x492.png)

这个对象适配器使用组合方式去将一个不匹配的接口适配到另一个接口。
适配器继承了客户端期望的目标接口,同时它持有适配者的一个实例。
这样使得客户端和适配者完全解耦。只有适配器知道它们两个(客户端、适配者)。

适配器模式类图

OffshoreAccount.java

package org.byron4j.cookbook.designpattern.adapter;


/**
 * 离岸账户
 */
public class OffshoreAccount {

    private double balance;

    /**税率*/
    private static final double TAX_RATE = 0.04;

    public OffshoreAccount(final double balance) {
        this.balance = balance;
    }

    public double getTaxRate() {
        return TAX_RATE;
    }

    public double getOffshoreBalance() {
        return balance;
    }

    public void debit(final double debit) {
        if (balance >= debit) {
            balance -= debit;
        }
    }

    public void credit(final double credit) {
        balance += balance;
    }
}


Account.java

package org.byron4j.cookbook.designpattern.adapter;

/**
 * 账户接口类型
 */
public interface Account {
    /**
     * 获取账户余额
     * @return
     */
    public double getBalance();

    /**
     * 是否可以透支
     * @return
     */
    public boolean isOverdraftAvailable();

    /**
     * 贷款; 贷款后账户余额增多
     * @param credit
     */
    public void credit(final double credit);
}


AbstractAccount.java

package org.byron4j.cookbook.designpattern.adapter;

public class AbstractAccount implements Account {
    /**
     * 账户余额
     */
    private double balance;
    /**
     * 是否可以透支
     */
    private boolean isOverdraftAvailable;

    public AbstractAccount(final double size) {
        this.balance = size;
    }

    @Override
    public double getBalance() {
        return balance;
    }

    @Override
    public boolean isOverdraftAvailable() {
        return isOverdraftAvailable;
    }

    public void setOverdraftAvailable(boolean isOverdraftAvailable) {
        this.isOverdraftAvailable = isOverdraftAvailable;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + " Balance=" + getBalance()
                + " Overdraft:" + isOverdraftAvailable();
    }

    @Override
    public void credit(final double credit) {
        balance += credit;
    }
}


PlatinumAccount.java

package org.byron4j.cookbook.designpattern.adapter;

/**
 * 白金帐户: 可以透支
 */
public class PlatinumAccount extends AbstractAccount {

    public PlatinumAccount(final double balance) {
        super(balance);
        // 可以透支
        setOverdraftAvailable(true);
    }
}


StandardAccount.java

package org.byron4j.cookbook.designpattern.adapter;

/**
 * 普通账户: 不能透支
 */
public class StandardAccount extends AbstractAccount {

    public StandardAccount(final double balance) {
        super(balance);
        // 不能透支
        setOverdraftAvailable(false);
    }
}



AccountAdapter.java

package org.byron4j.cookbook.designpattern.adapter;

/**
 * 账户适配器; 适配器继承于目标账户。
 * 适配器(转接头)的目标是将离岸账户(会议室中的Mac电脑)转为 AbstractAccount(可以连接投影仪)
 */
public class AccountAdapter extends AbstractAccount {

    /**需要被适应的账户--适配者*/
    private OffshoreAccount offshoreAccount;

    /**
     *
     * @param offshoreAccount  适配者--会议室中的 mac 电脑
     */
    public AccountAdapter(final OffshoreAccount offshoreAccount) {
        super(offshoreAccount.getOffshoreBalance());

        // 适配器持有适配者的引用
        this.offshoreAccount = offshoreAccount;
    }

    /**
     * 计算扣除税款后的离岸账户余额
     * @return
     */
    @Override
    public double getBalance() {
        // 离岸税率
        final double taxRate = offshoreAccount.getTaxRate();

        // 离岸账户余额
        final double grossBalance = offshoreAccount.getOffshoreBalance();

        // 需要扣除的税款
        final double taxableBalance = grossBalance * taxRate;

        // 扣除离岸税款后的账户余额
        final double balanceAfterTax = grossBalance - taxableBalance;

        return balanceAfterTax;
    }
}


AdapterTest.java


package org.byron4j.cookbook.designpattern;

import org.byron4j.cookbook.designpattern.adapter.AccountAdapter;
import org.byron4j.cookbook.designpattern.adapter.OffshoreAccount;
import org.byron4j.cookbook.designpattern.adapter.StandardAccount;
import org.junit.Test;

public class AdapterTest {
    @Test
    public void test(){
        StandardAccount sa = new StandardAccount(2000);
        System.out.println("Account Balance= " + sa.getBalance());

        //Calling getBalance() on Adapter
        AccountAdapter adapter = new AccountAdapter(new OffshoreAccount(2000));
        System.out.println("Account Balance= " + adapter.getBalance());
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容