【設(shè)計(jì)模式】之適配器模式

適配器模式

什么是適配器模式

  • 適配器模式屬于結(jié)構(gòu)型模式,可以使得兩個(gè)不匹配的接口可以協(xié)同工作。
  • 適配器模式允許兩個(gè)不匹配的類通過將其中一個(gè)接口類型轉(zhuǎn)換成另一個(gè)客戶端期望的接口類型,從而達(dá)到二者協(xié)同工作。
  • 適配器模式也叫包裝器。
    適配器模式在 Gang of Four 書中原始的定義如下:

將一個(gè)類的接口類型轉(zhuǎn)換成另一個(gè)客戶端期望的接口類型。
適配器可以讓多個(gè)類協(xié)同工作即使他們本來是不匹配的接口類型。

適配器模式的應(yīng)用場景

  • 考慮一個(gè)這樣的場景,你在印度購買了一個(gè)輕便的筆記本,最近你剛搬到英國。但是英國的電子插座和印度的不一樣。因此,你的筆記本不能直接工作了。
    你必須去購買一個(gè)適配器,可以為你的印度筆記本可以在英國的插座上充電。

  • 當(dāng)你有一個(gè)需要與新系統(tǒng)集成的遺留接口時(shí),新系統(tǒng)不能直接接收遺留庫的工作方式。由于遺留庫不再進(jìn)行開發(fā)了,所以我們需要使用適配器促使兩種不同的類型進(jìn)行工作。

  • 你使用 Mac 時(shí),經(jīng)常需要轉(zhuǎn)接頭才能連接到會(huì)議室的投影儀,這個(gè)轉(zhuǎn)接頭,就是適配器,使得原本 Mac 、投影儀互不相容的兩個(gè)物件可以協(xié)同工作。

適配器模式的特點(diǎn)

  • 客戶端通過使用目標(biāo)接口調(diào)用適配器的方法向適配器發(fā)起請求。
  • 適配器通過適配器接口將請求轉(zhuǎn)換成適配者的一個(gè)或多個(gè)調(diào)用。
  • 客戶端收到調(diào)用結(jié)果,并且不感知存在一個(gè)適配器在做這個(gè)轉(zhuǎn)換工作。

何時(shí)使用適配器模式

  • 如果你想要將已經(jīng)存在的類和他們的接口類型去匹配你最后需要的接口類型,就可以使用適配器模式。
  • 如果你想創(chuàng)建可重用類以幫助在不匹配的兩個(gè)類之間進(jìn)行接口式交互。

適配器模式示例

勞埃德銀行是一家提供全球性服務(wù)的國際性銀行。境外賬戶持有人的稅率為 0.03%。
在印度,它提供2種類型的賬戶,普通和白金。稅法不適用于印度賬戶。
現(xiàn)在離岸賬戶就匹配不了印度賬戶了。
所以需要設(shè)計(jì)出一個(gè)賬戶適配器 AccountAdapter 促使2種不同的賬戶類型還可以繼續(xù)一塊工作。

這個(gè)示例的交互圖如下所示。
在這里,客戶端僅僅需要調(diào)用適配器的 getBalance() 方法。
適配器調(diào)用適配者的 getOffshoreBalance() 方法并返回客戶端期望的結(jié)果。
適配器內(nèi)部的 getBalance() 方法將會(huì)通過扣除稅金來計(jì)算賬戶余額。

適配器模式時(shí)序圖

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

這個(gè)對象適配器使用組合方式去將一個(gè)不匹配的接口適配到另一個(gè)接口。
適配器繼承了客戶端期望的目標(biāo)接口,同時(shí)它持有適配者的一個(gè)實(shí)例。
這樣使得客戶端和適配者完全解耦。只有適配器知道它們兩個(gè)(客戶端、適配者)。

適配器模式類圖

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;

/**
 * 賬戶適配器; 適配器繼承于目標(biāo)賬戶。
 * 適配器(轉(zhuǎn)接頭)的目標(biāo)是將離岸賬戶(會(huì)議室中的Mac電腦)轉(zhuǎn)為 AbstractAccount(可以連接投影儀)
 */
public class AccountAdapter extends AbstractAccount {

    /**需要被適應(yīng)的賬戶--適配者*/
    private OffshoreAccount offshoreAccount;

    /**
     *
     * @param offshoreAccount  適配者--會(huì)議室中的 mac 電腦
     */
    public AccountAdapter(final OffshoreAccount offshoreAccount) {
        super(offshoreAccount.getOffshoreBalance());

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

    /**
     * 計(jì)算扣除稅款后的離岸賬戶余額
     * @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());
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容