将一个类的接口类型转换成另一个客户端期望的接口类型。 适配器可以让多个类协同工作即使他们本来是不匹配的接口类型。
劳埃德银行是一家提供全球性服务的国际性银行。境外账户持有人的税率为 0.03%。 在印度,它提供2种类型的账户,普通和白金。税法不适用于印度账户。 现在离岸账户就匹配不了印度账户了。 所以需要设计出一个账户适配器 AccountAdapter 促使2种不同的账户类型还可以继续一块工作。
这个示例的交互图如下所示。
在这里,客户端仅仅需要调用适配器的 getBalance()
方法。
适配器调用适配者的 getOffshoreBalance()
方法并返回客户端期望的结果。
适配器内部的 getBalance() 方法将会通过扣除税金来计算账户余额。
这个对象适配器使用组合方式去将一个不匹配的接口适配到另一个接口。 适配器继承了客户端期望的目标接口,同时它持有适配者的一个实例。 这样使得客户端和适配者完全解耦。只有适配器知道它们两个(客户端、适配者)。
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;
}
}
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);
}
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;
}
}
package org.byron4j.cookbook.designpattern.adapter;
/**
* 白金帐户: 可以透支
*/
public class PlatinumAccount extends AbstractAccount {
public PlatinumAccount(final double balance) {
super(balance);
// 可以透支
setOverdraftAvailable(true);
}
}
package org.byron4j.cookbook.designpattern.adapter;
/**
* 普通账户: 不能透支
*/
public class StandardAccount extends AbstractAccount {
public StandardAccount(final double balance) {
super(balance);
// 不能透支
setOverdraftAvailable(false);
}
}
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;
}
}
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());
}
}