设计模式学习—适配器模式

1、什么是适配器模式?

​ 有时,当我们试图将遗留代码与新代码集成时,或者在代码中更改第三方API时,会出现两个对象不匹配的情况。这是由于两个对象的接口不兼容造成的。适配器模式允许您调整对象或类向另一个对象或类公开的内容。它将类的接口转换为客户机期望的另一个接口。它让那些由于接口不兼容而无法协同工作的类一起工作。它允许在不直接修改对象和类的情况下修复对象和类之间的接口。您可以将适配器看作是一个实际的适配器,它用于连接两个不能直接连接的不同设备。

2、场景分析

​ 举个例子:软件开发人员Max在一家电子商务网站工作。该网站允许用户在线购物和支付,该网站与第三方支付集成,用户可以通过第三方支付使用信用卡支付账单。一切都进行得很顺利,直到他的经理打电话给他要求改变项目。经理告诉他,他们计划更改支付供应商,他必须在代码中实现这一点。这里出现的问题是,站点本来使用的是Xpay支付。新供应商PayD只允许PayD类型的对象允许该流程。Max不想改变整个100个类的集合,这些类都引用了一个类型为XPay的对象。这也增加了项目的风险,该项目已经在生产中运行。由于代码的两个不同部分之间存在不兼容的接口,所以出现了这个问题。为了使流程正常工作,Max需要找到一种方法使代码与供应商提供的API兼容。

3、代码实现

package com.zte.test.adapter;
public interface PayD {
    public String getCustCardNo();
    public String getCardOwnerName();
    public String getCardExpMonthDate();
    public Integer getCVVNo();
    public Double getTotalAmount();
    public void setCustCardNo(String custCardNo);
    public void setCardOwnerName(String cardOwnerName);
    public void setCardExpMonthDate(String cardExpMonthDate);
    public void setCVVNo(Integer cVVNo);
    public void setTotalAmount(Double totalAmount);
}

​ 它包含一组setter和getter方法,用于获取关于信用卡和客户名的信息。这个Xpay接口在代码中实现,代码用于实例化这种类型的对象,并将该对象公开给供应商的API。下面的类定义了Xpay接口的实现。

package com.zte.test.adapter;

public class XpayImpl implements Xpay {
    private String creditCardNo;
    private String customerName;
    private String cardExpMonth;
    private String cardExpYear;
    private Short cardCVVNo;
    private Double amount;

    @Override
    public String getCreditCardNo() {
        return creditCardNo;
    }

    @Override
    public String getCustomerName() {
        return customerName;
    }

    @Override
    public String getCardExpMonth() {
        return cardExpMonth;
    }

    @Override
    public String getCardExpYear() {
        return cardExpYear;
    }

    @Override
    public Short getCardCVVNo() {
        return cardCVVNo;
    }

    @Override
    public Double getAmount() {
        return amount;
    }

    @Override
    public void setCreditCardNo(String creditCardNo) {
        this.creditCardNo = creditCardNo;
    }

    @Override
    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    @Override
    public void setCardExpMonth(String cardExpMonth) {
        this.cardExpMonth = cardExpMonth;
    }

    @Override
    public void setCardExpYear(String cardExpYear) {
        this.cardExpYear = cardExpYear;
    }

    @Override
    public void setCardCVVNo(Short cardCVVNo) {
        this.cardCVVNo = cardCVVNo;
    }

    @Override
    public void setAmount(Double amount) {
        this.amount = amount;
    }
}
package com.zte.test.adapter;
public interface PayD {
    public String getCustCardNo();
    public String getCardOwnerName();
    public String getCardExpMonthDate();
    public Integer getCVVNo();
    public Double getTotalAmount();
    public void setCustCardNo(String custCardNo);
    public void setCardOwnerName(String cardOwnerName);
    public void setCardExpMonthDate(String cardExpMonthDate);
    public void setCVVNo(Integer cVVNo);
    public void setTotalAmount(Double totalAmount);
}

可以看到,这个接口有一组不同的方法,需要在代码中实现。但是Xpay是由大部分代码创建的,更改整个类集是非常困难和有风险的。我们需要一些方法,能够满足供应商的要求,以便处理付款,并作出较少或没有改变,在目前的代码。方法由适配器模式提供。我们将创建一个类型为PayD的适配器,它封装了一个Xpay对象。

package com.zte.test.adapter;

public class XpayToPayDAdapter implements PayD {
    private String custCardNo;
    private String cardOwnerName;
    private String cardExpMonthDate;
    private Integer cVVNo;
    private Double totalAmount;
    private final Xpay xpay;

    public XpayToPayDAdapter(Xpay xpay) {
        this.xpay = xpay;
        setProp();
    }

    @Override
    public String getCustCardNo() {
        return custCardNo;
    }

    @Override
    public String getCardOwnerName() {
        return cardOwnerName;
    }

    @Override
    public String getCardExpMonthDate() {
        return cardExpMonthDate;
    }

    @Override
    public Integer getCVVNo() {
        return cVVNo;
    }

    @Override
    public Double getTotalAmount() {
        return totalAmount;
    }

    @Override
    public void setCustCardNo(String custCardNo) {
        this.custCardNo = custCardNo;
    }

    @Override
    public void setCardOwnerName(String cardOwnerName) {
        this.cardOwnerName = cardOwnerName;
    }

    @Override
    public void setCardExpMonthDate(String cardExpMonthDate) {
        this.cardExpMonthDate = cardExpMonthDate;
    }

    @Override
    public void setCVVNo(Integer cVVNo) {
        this.cVVNo = cVVNo;
    }

    @Override
    public void setTotalAmount(Double totalAmount) {
        this.totalAmount = totalAmount;
    }

    private void setProp() {
        setCardOwnerName(this.xpay.getCustomerName());
        setCustCardNo(this.xpay.getCreditCardNo());
        setCardExpMonthDate(this.xpay.getCardExpMonth() + "/" + this.xpay.
                getCardExpYear());
        setCVVNo(this.xpay.getCardCVVNo().intValue());
        setTotalAmount(this.xpay.getAmount());
    }
}
package com.zte.test.adapter;

public class RunAdapterExample {
    public static void main(String[] args) {
// Object for Xpay
        Xpay xpay = new XpayImpl();
        xpay.setCreditCardNo("4789565874102365");
        xpay.setCustomerName("Max Warner");
        xpay.setCardExpMonth("09");
        xpay.setCardExpYear("25");
        xpay.setCardCVVNo((short) 235);
        xpay.setAmount(2565.23);
        PayD payD = new XpayToPayDAdapter(xpay);
        testPayD(payD);
    }

    private static void testPayD(PayD payD) {
        System.out.println(payD.getCardOwnerName());
        System.out.println(payD.getCustCardNo());
        System.out.println(payD.getCardExpMonthDate());
        System.out.println(payD.getCVVNo());
        System.out.println(payD.getTotalAmount());
    }
}

​ 在上面的代码中,我们创建了一个适配器(XpayToPayDAdapter)。适配器实现了PayD接口,因为需要模仿PayD类型的对象。对象通过其构造函数传递到适配器。现在请注意,我们有两种不兼容的接口类型,为了使代码工作,我们需要使用适配器将它们组合在一起。这两个接口有一组不同的方法。但是这些接口的唯一目的非常相似,即向特定的供应商提供客户和信用卡信息。

4、何时使用适配器模式?

适配器模式应该在以下情况下使用:

​ 1、存在现有类,且其接口与您需要的接口不匹配。

​ 2、您想要创建一个可重用的类,该类与不相关的或不可预见的类协作,即不一定具有兼容接口的类。

​ 3、有几个现有的子类要使用,但是通过子类化每个子类来调整它们的接口是不切实际的。对象适配器可以调整其父类的接口。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容