美文网首页
生活中的设计模式之适配器模式

生活中的设计模式之适配器模式

作者: chzne | 来源:发表于2022-01-14 17:06 被阅读0次

    定义

    The adapter pattern convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

    将一个类的接口转换成客户期望的另一个接口,使原本不兼容的接口可以一起工作。

    小故事

    前不久,我开发了一套支付系统,可以支持用户使用积分支付。不久后,新增了微信支付,但微信提供的支付SDK接口和我们系统的Pay接口不一样,所以我便增加if...else语句来扩展新的支付方式。再之后,又增加了支付宝......

    
    public class Client {
    
        public static void main(String[] args) {
            if(args[0].equals("积分")){
                PointPay pay = new PointPay();
                pay.pay(args);
            }else if(args[0].equals("微信")){
                WXSDKPay wxsdkPay= new WXSDKPay();
                wxsdkPay.payByWX(convert(args));
            }else if(args[0].equals("支付宝")){
                ALISDKPay alisdkPay= new ALISDKPay();
                alisdkPay.payByALI(convert(args));
            }
        }
    }
    
    

    问题

    故事中,积分支付、微信支付、支付宝三者的功能都是一样的,但接口却不一样具体地说是操作(行为、方法)不一样。

    当两个对象的功能一样,操作不一样时,如果我们使用if...else这种差异化的处理方式操作对象,那么一旦发生扩展就得修改客户端的代码,但如果不允许我们修改客户端代码,又怎么办呢?

    因此,为了避免上面的问题,我们应该使用适配器模式——将不一样的操作转换成客户端期望的统一操作。

    方案

    既然上面"差异化的处理方式"会导致很多问题,那么我们应该统一处理方式。最直接的方式是让适配者(微信支付)继承目标接口(Payment)这样客户就能统一操作这样对象了。
    但是,如果我们不能修改适配者呢?那么我们可以新建一个实现目标接口并组合了适配者的类,让它将适配者的操作转换成客户端期望的操作,这个类被称为适配器,这种方式即是适配器模式。

    
    public class WXPayAdapter implements Payment{
        protected WXSDKPay wxsdkPay;
    
        public WXPayAdapter(){
            wxsdkPay = new WXSDKPay();
        }
    
        @Override
        public void pay(String[] args) {
            //将对象的payByWX操作转换成客户期望的pay操作
            wxsdkPay.payByWX(convert(args));
        }
    }
    
    

    在适配器模式中,适配器位于客户端和适配者中间,适配者对客户端不可见,因此适配者本身的变化不会影响客户端;适配器的接口和客户端期望的接口一致,因此我们可以在不改变客户端代码的前提下,通过适配器复用已存在的适配者,前提是客户端采用多态访问目标对象。

    应用

    接下来,我们使用适配器模式重构一下"支付系统",使其可以复用与系统不兼容的对象。

    首先,我们的支付系统已经存在一个支付接口以及积分支付类。

    
    //支付接口
    public interface Payment {
        public void pay(String[] args);
    }
    
    //支付接口
    public class PointPay implements Payment{
        @Override
        public void pay(String[] args) {
            System.out.println("使用积分支付");
        }
    }
    
    

    然后,为了扩展新的支付方式WXSDKPay、ALISDKPay,我们需要为它们创建对应的适配器。

    
    /**微信支付适配器*/
    public class WXPaymentAdapter implements Payment {
        protected WXSDKPay wxsdkPay;
    
        public WXPaymentAdapter(WXSDKPay wxsdkPay){
            this.wxsdkPay = wxsdkPay;
        }
    
        @Override
        public void pay(String[] args) {
            wxsdkPay.payByWX(convert(args));
        }
    }
    
    /**支付宝适配器*/
    public class ALIPaymentAdapter implements Payment {
        protected ALISDKPay alisdkPay;
    
        public ALIPaymentAdapter(ALISDKPay alisdkPay){
            this.alisdkPay = alisdkPay;
        }
    
        @Override
        public void pay(String[] args) {
            alisdkPay.payByALI(convert(args));
        }
    }
    
    
    

    最后,我们在看看客户端如何使用适配器模式。

    public class Client {
    
        public static Payment getPayment(String method){
            //这里读者可以理解为动态获取的
            PointPay pay = new PointPay();
            ALIPaymentAdapter wxAdapter = new ALIPaymentAdapter(new WXSDKPay);
            WXPaymentAdapter aliAdapter = new WXPaymentAdapter(new ALISDKPay);
            return aliAdapter;
        }
    
        public static void main(String[] args) {
            //操作方式是统一的
            Payment pay = getPayment(args[0]);
            pay.pay(args);
        }
    
    
    }
    
    

    结构

    avatar

    目标接口(Target):声明客户端统一的操作以及适配器需要实现的接口,。

    适配者(Adaptee):是客户端期望操作但与目标接口不一致的对象。

    适配器(Adapter):实现了目标接口,负责将适配者的操作转成客户期望的操作,它持有适配者。

    客户端(Client):负责操作目标接口的对象,它不关心目标接口的实现类是系统提供的还是由适配器包装而成的。

    实现类型

    对象适配器

    对象适配器(Object Adapter)通过组合适配者(Adaptee)和实现目标接口(Target)的方式,给适配者新增目标接口。

    avatar
    
    //适配者
    public class Adaptee {
    
        public void specificRequest(){}
    }
    
    //目标接口
    public interface Target {
        public void request();
    }
    
    //1、实现Target
    public class Adapter implements Target{
        protected Adaptee adaptee;
        //2、组合Adaptee
        public Adapter(Adaptee adaptee){
            this.adaptee = adaptee;
        }
        @Override
        public void request() {
            //3、转换请求
            adaptee.specificRequest();
        }
    }
    
    public class Client {
    
        public void main(String[] args){
            //用适配器包装适配者,将其伪装成目标接口
            Target target = new Adapter(new Adaptee());
            
            //符合客户的期望
            target.request();
        }
    }
    
    类适配器

    类适配器(Class Adapter)和对象适配器主要的差异是,它通过继承的方式而对象适配器通过组合的方式。

    
    //适配者
    public class Adaptee {
    
        public void specificRequest(){}
    }
    
    //目标接口
    public interface Target {
        public void request();
    }
    
    //1、继承适配者;2、实现目标接口
    public class ClassAdapter extends Adaptee implements Target{
        @Override
        public void leaveRequest() {
            //3、转发请求——调用适配器继承下来的方法specificRequest
            specificRequest();
        }
    }
    
    public class Client {
        public void main(String[] args){
            //客户都不知道有适配者的存在
            Target target = new ClassAdapter();
            target.leaveRequest();
    
        }
    }
    
    

    总结

    当一个对象的接口和系统的接口不一致,而我们又想使用这个对象时,那么我们可以使用适配器将这个对象包装成与系统接口兼容的对象。
    这样,可以使我们在不修改系统的前提下,复用已经存在的对象。

    相关文章

      网友评论

          本文标题:生活中的设计模式之适配器模式

          本文链接:https://www.haomeiwen.com/subject/hgoacrtx.html