zoukankan      html  css  js  c++  java
  • Java设计模式——适配器模式(Adapter)

    目的:把源类型适配为目标类型,以适应客户端(Client)的需求;此处我们把目标接口的调用方视为客户端

    使用场景:需要对类型进行由源类型到目标类型转换的场景中

    前置条件已有客户端

    //Client 一个调用目标接口的方法
    Class ClientInvoking {
    
        static void invoke(TargetInterface target) {
            String value = target.getMark();
            System.out.println(value);
        }
    
    }

    常用的几种模式

    模式一:存在目标接口,且存在已有方法

    //目标接口
    public interface TargetInterface {
        
        public String getMark();
    
        public String getInfo();
    
    }
    //已有类及方法
    public class ExistClass {
    
        public String sayHello() {
            return "Hello";
        }
          
        public String sayWorld() {
            return "World";
        }
    }

    我们假设ExistClass返回的字符串正好是我们的客户端需要用到的,但客户端需要的是通过一个TargetInterface类型的对象来获取,因此我们需要想办法对已有类进行适配,使其能够满足客户端的需求;该模式下存在两种应用方案:

    方案1.类适配器模式

    //适配器
    public class ClassAdapter extends ExistClass implements TargetInterface {
        
        public int getMark() {
            String value = this.sayHello();
            return value;
        }
        
        public int getInfo() {
            String value = this.sayWorld();
            return value;
        }
        
    }
    //客户端调用
    TargetInterface target = new ClassAdapter();
    ClientInvoking.invoke(target);

    由Java接口的概念可知,ClassAdapter作为TargetInterface的实现类,能够向上转型为TargetInterface类型,适应了客户端的需求。

    方案2.对象适配器模式

    //适配器
    public class ClassAdapter implements TargetInterface {
        
        private ExistClass exist;
        
        public ClassAdapter(ExistClass existClass) {
            this.exist = existClass;
        }
        
        public int getMark() {
            String value = exist.sayHello();
            return value;
        }
        
        public int getInfo() {
            String value = exist.sayWorld();
            return value;
        }
        
    }
    //客户端调用
    TargetInterface target = new ClassAdapter(new ExistClass());
    ClientInvoking.invoke(target);

    该方案与类适配器模式类似,只是不采用继承而采用持有对象的方式,更加灵活,扩展性更强。

    模式二:不存在目标接口,但是存在目标类,且存在已有方法

    我们先对前置条件中的客户端进行改造,如下:

    Class ClientInvoking {
    
        static void invoke(TargetClass target) {
            String value = target.getMark();
            System.out.println(value);
        }
    
    }

    改造后,invoke方法需要一个TargetClass类的对象作为参数;下面是目标类和已有类

    //目标类
    public class Class {
        
        public String getMark() {
            return "yes";
        }
    
        public String getInfo() {
            return "no";
        }
    
    }
    //已有类及方法
    public class ExistClass {
    
        public String sayHello() {
            return "Hello";
        }
          
        public String sayWorld() {
            return "World";
        }
    }

    我们假设ExistClass返回的字符串正好是我们的客户端需要用到的,且客户端中需要的TargetClass对象的内容已经过时,因此我们需要相办法对ExistClass进行适配,以适应客户端的需求;

    //适配器
    public class ClassAdapter extends TargetClass {
        
        private ExistClass exist;
        
        public ClassAdapter(ExistClass existClass) {
            this.exist = existClass;
        }
        
        public int getMark() {
            String value = exist.sayHello();
            return value;
        }
        
        public int getInfo() {
            String value = exist.sayWorld();
            return value;
        }
        
    }
    //客户端调用
    TargetClass target = new ClassAdapter(new ExistClass());
    ClientInvoking.invoke(target);

    在该种模式下,设计到两个类,且最后要进行向上转型,根据Java的单继承机制,我们只能通过持有对象的形式,即对象适配器模式。

    模式三:缺省适配器模式

    该模式中,不存在显式的目标类型,而仅有源类型;之所以需要用到这个,往往是因为源类型中提供了太多我们并不需要的东西,我们需要通过适配器模式进行定制化。以WindowListener作为例子讲解:

    //WindowListener源码
    public interface WindowListener extends EventListener {
        public void windowOpened(WindowEvent e);
        public void windowClosing(WindowEvent e);
        public void windowClosed(WindowEvent e);
        ...
    }
    //添加监听器的例子
    Frame frame = new Frame();
    frame.addWindowListener(new WindowListener() {
        @Override
        public void windowOpened(WindowEvent e) {
                
        }
    
        @Override
        public void windowClosing(WindowEvent e) {
    
        }
    
        @Override
        public void windowClosed(WindowEvent e) {
    
        }
        ...
    })

    这样的代码,看起来很繁琐;比如说我只需要监听正在关闭的事件,却生成了许多与此无关的模板代码,降低了代码的可读性,鉴于此,我们来做下定制,只监听一个接口;

    我们首先提供一个抽象类实现了该接口,并为所有监听器提供空实现;然后再用抽象类的子类重写窗口正在关闭的监听器的实现,代码如下:

    //适配器
    public abstract ListenerAdapter implements WindowListener {
        public void windowOpened(WindowEvent e) {}
        public void windowClosing(WindowEvent e) {}
        public void windowClosed(WindowEvent e) {}
        ...
    }
    //重写方法
    public class OverrideWindowClosing extends ListenerAdapter {
        
        @Override
        public void windowClosing(WindowEvent e) {
            //TODO
        }
        
    }
    //客户端调用
    frame.addWindowListener(new OverrideWindowClosing());

    该方式简化了接口,提高了代码可读性。最重要的是,我们实现了对接口的定制,可以只做自己关心的事情。

  • 相关阅读:
    数据分析人员常犯的五大错误以及预防方法
    SAS中的Order By - Proc Sort
    SAS中的Order By - Proc Sort
    安全数据分析理念的变化
    安全数据分析理念的变化
    spss如何选择需要的变量?
    更改VS2010的[默认开发语言]
    POJ 1273 Drainage Ditches (网络最大流)
    HLS图像处理系列——肤色检測
    并发问题:大数据量的訪问
  • 原文地址:https://www.cnblogs.com/lurker-yaojiang/p/9774123.html
Copyright © 2011-2022 走看看