zoukankan      html  css  js  c++  java
  • 设计模式总结-适配器模式

    什么是适配器模式

    适配器模式(Adapter Pattern)是指将一个类的接口转换成客户期望的另一个接口,使原本的接口不兼容的类可以一起工作,属于结构型设计模式。
    适配器模式主要有3个角色:
    被适配者(Adaptee):适配者即被适配的角色
    比如买了一个欧标吹风机,和国内的标准并不匹配。这时,被适配的角色即为国内的插座
    适配器(Adapter):适配器可以调用适配者转换为目标接口,即作为一个转换器,将一个不可使用的接口转换为可用的接口
    果断的上了某东买了个接口转换器
    目标角色(Target):目标角色即为适配器要转换成的目标接口
    转换器提供的欧标插孔就是这里我们所说的目标角色或者目标接口

    适配器模式的优点

    1. 将被适配者和目标角色解耦,引入适配器类,不改动原有代码
    2. 提高类的复用程度
    3. 灵活性更好

    案例的简单实现

    以上文中的欧标插头为例
    1、目标接口

    /**
     * Description :   .
     *
     * @author : laoyeye.net
     * @date : Created in 2020/7/25 20:56
     */
    public interface ChinaSocket {
    
        void socketByChina();
    }
    

    2、目标接口实现

    /**
     * Description :   .
     *
     * @author : laoyeye.net
     * @date : Created in 2020/7/25 21:08
     */
    public class ChinaSocketImpl implements ChinaSocket {
    
        @Override
        public void socketByChina() {
            System.out.println("插入国标电源");
        }
    }
    

    3、被适配者,欧标电源接口

    /**
     * Description :   .
     *
     * @author : laoyeye.net
     * @date : Created in 2020/7/25 20:56
     */
    public interface EuropeSocket {
    
        void socketByEurope();
    
    }
    

    4、适配器,国标转欧标

    /**
     * Description :   .
     *
     * @author : laoyeye.net
     * @date : Created in 2020/7/25 21:00
     */
    public class ChinaToEuAdapter implements EuropeSocket {
    
        /**
         * 需要适配的接口
         */
        private ChinaSocket chinaSocket;
    
        public ChinaToEuAdapter(ChinaSocket chinaSocke) {
            this.chinaSocket = chinaSocke;
        }
    
        @Override
        public void socketByEurope() {
            System.out.println("适配器,国标转为欧标");
            chinaSocket.socketByChina();
        }
    }
    
    

    5、运行实现

    /**
     * Description :   .
     *
     * @author : zhangzhuo
     * @date : Created in 2020/7/25 21:03
     */
    public class HairDryer {
    
        /**
         * 期望的欧标插头接口
         */
        private EuropeSocket europeSocket;
    
        public HairDryer(EuropeSocket europeSocket) {
            this.europeSocket = europeSocket;
        }
    
        public void work() {
            europeSocket.socketByEurope();
            System.out.println("开始吹头发了");
        }
    
        public static void main(String[] args) {
            // 国标插座
            ChinaSocket chinaSocket = new ChinaSocketImpl();
            //适配器转换
            ChinaToEuAdapter chinaToEuAdapter = new ChinaToEuAdapter(chinaSocket);
            HairDryer hairDryer = new HairDryer(chinaToEuAdapter);
            // 工作
            hairDryer.work();
        }
    
    }
    

    效果:

    适配器,国标转为欧标
    插入国标电源
    开始吹头发了
    

    哇哦,接口成功实现转换,吹风机终于用起来了。

    模拟迭代接口的冲突问题

    1、目标接口
    假设上线时,我们有个接口支持的是map类型。经过几个迭代后,新上一个系统,要求传递参数的结构为list类型。
    这时候我们不能修改以前使用接口的系统。就只能通过适配器模式支持此种形式的参数。

    /**
     * Description :   .
     * 历史接口
     * @author : laoyeye.net
     * @date : Created in 2020/8/1 23:12
     */
    public class OrderService {
    
        /**
         * 原接口入参为map类型
         * 这时候随着版本的迭代,要求我们接口参数支持list类型
         * 因为很多上层系统调用,此接口不能修改
         * 这时候就可以用到适配器模式
         * @param map
         */
        public void createOrderByMap(Map<String, String> map) {
            for(String value : map.values()){
                System.out.println(value);
            }
        }
    
    }
    

    2、适配器支持list类型

    /**
     * Description :   .
     * 适配器
     * @author : laoyeye.net
     * @date : Created in 2020/8/1 23:16
     */
    public class ListAdapter extends HashMap {
    
        private List list;
    
        public ListAdapter(List list) {
            this.list = list;
        }
    
    
        @Override
        public Collection values() {
            return list;
        }
    }
    

    3、被适配者list接口参数执行实现

    /**
     * Description :   .
     * 被适配者
     * @author : laoyeye.net
     * @date : Created in 2020/8/1 23:17
     */
    public class App {
        public static void main(String[] args) {
            OrderService orderService = new OrderService();
            System.out.println("===map类型的接口参数===");
            Map map = new HashMap();
            map.put("laoyeye","laoyeye.net");
            map.put("laoyeye2","小卖铺的老爷爷");
            // 原接口支持map类型
            orderService.createOrderByMap(map);
    
            System.out.println("===list类型的接口参数===");
            List<String> list = Arrays.asList("laoyeye.net", "小卖铺的老爷爷");
            // 使用适配器实现转换
            ListAdapter listAdapter = new ListAdapter(list);
            // 可以支持list类型
            orderService.createOrderByMap(listAdapter);
    
        }
    }
    

    效果:

    ===map类型的接口参数===
    laoyeye.net
    小卖铺的老爷爷
    ===list类型的接口参数===
    laoyeye.net
    小卖铺的老爷爷
    

    这样我们就实现了历史的map接口,支持新的list数据类型了,是不是很神奇

    总结

    适配器模式我目前工作中其实很少用到,过多的适配器也不利于系统的维护

    1. 适配器适合已经存在的类,它的方法和需求不匹配(方法结果相同或相似)的情况。
    2. 适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案。

    最后,大家有没有感觉上面那个案例,其实我们上次讲过的装饰者模式也可以实现呢。的确,这两种模式都可以实现类似的效果,但却又有所不同,比如:
    装饰者模式适合在不改变原有对象的基础上,将功能附加在对象上,用于扩展一个类的功能。而本文所讲的适配器模式主要适合在不改变原有接口的前提下,解决接口不兼容的问题。总得来说两者的主要区别就在于一个是装饰,一个是来解决接口不兼容的问题,记住这两点,相信在使用上就不会有疑问了

  • 相关阅读:
    在source insight中 添加新的文件类型
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Convention插件与约定支持
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:配置Struts2的异常处理
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:配置处理结果(2)
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:配置处理结果(1)
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:配置Action(2)
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:配置Action(1)
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:实现Action
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Struts2的下载与安装基础
    吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Tomcat8的WebSocket支持
  • 原文地址:https://www.cnblogs.com/laoyeye/p/13378415.html
Copyright © 2011-2022 走看看