zoukankan      html  css  js  c++  java
  • 适配器模式

    在讲述这个模式之前,我们先看一个案例:中国球员去NBA打篮球

    中国球员去NBA打篮球,可是他不懂英语,所以听不懂教练安排的战术,所以现在有三种解决方式

    1、球员学会英语。2、教练学会中文。3、请个翻译。

    1和2是长久之计,但不能解决迫在眉睫的问题。请个翻译是短暂的更好的选择。

    放在软件设计层面上,这就叫做适配器模式。http://www.runoob.com/design-pattern/adapter-pattern.html

    将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

    在软件开发中,也就是系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配,适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。

    在 GoF 的设汁模式中,对适配器模式讲了两种类型,类适配器模式和对象适配器模式,由于类适配器模式通过多重继承对一个接口与另一个接口进行匹配,而JAVA语言不支持多重继承,也就是一个类只有一个父类,所以我们这里主要讲的是对象适配器。

    Target(这是客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口)代码如下:

    public class Target {
        public void request() {
            System.out.println("普通请求");
        }
    }

    Adaptee(需要适配的类)代码如下:

    public class Adaptee {
        public void specialRequest(){
            System.out.println("特殊请求");
        }
    }

    Adapter(通过在内部包装一个Adaptee对象,把原接口转换成目标接口)代码如下:

    public class Adapter extends Target{
        private Adaptee adaptee = new Adaptee();//建立一个私有的Adaptee对象
        
        @Override
        public void request() {
            //这样就可以把表面上调用request()方法变成实际调用的specialRequest()
            adaptee.specialRequest();
        }
    }

    测试方法

    public class Test {
        public static void main(String[] args) {
         //对main方法来说,调用的就是Target的request()        
         Target target = new Target();
            target.request();
        }
    }

    看起来是不是很简单,是不是跟一句俗语很像“挂羊头卖狗肉”。

    何时使用适配器模式?

    在想使用一个已经存在的类,但如果它的接口,也就是它的方法和你的要求不相同时,就应该考虑用适配器模式。两个类所做的事情相同或相似,但是具有不同的接口时要使用它。而且由于类都共亨同一个接口,代码可以统一调用同一接口就行了,这样应该可以更简单、更直接、更紧凑。

    其实用适配器模式也是无奈之举,很有点‘亡羊补牢’的感觉,没办法呀,是软件就有维护的一天,维护就有可能会因不同的开发人员、不同的产品、不同的厂家而造成功能类似而接口不同的情况,此时就是适配器模式大展拳脚的时候了。

    现在把教练给球员们分配任务的例子用适配器模式实现

    球员类

    public abstract class Player {
        protected String name;
        public Player(String name) {
            this.name = name;
        }
        //进攻和防守方法
        public abstract void attack();
        public abstract void defense();
    }

    后卫、中锋、前锋类

    //前锋
    public class Forwards extends Player {
        public Forwards(String name) {
            super(name);
        }
        @Override
        public void attack() {
            System.out.println("前锋:"+name+"进攻");
        }
        @Override
        public void defense() {
            // TODO Auto-generated method stub
            System.out.println("前锋:"+name+"防守");
        }
    }
    //中锋
    public class Center extends Player {
        public Center(String name) {
            super(name);
        }
        @Override
        public void attack() {
            System.out.println("中锋:"+name+"进攻");
        }
    
        @Override
        public void defense() {
            // TODO Auto-generated method stub
            System.out.println("中锋:"+name+"防守");
        }
    }
    //后卫
    public class Guards extends Player {
        public Guards(String name) {
            super(name);
        }
        @Override
        public void attack() {
            System.out.println("后卫:"+name+"进攻");
        }
        @Override
        public void defense() {
            // TODO Auto-generated method stub
            System.out.println("后卫:"+name+"防守");
        }
    }

    测试方法

    public class Test {
        public static void main(String[] args) {
            Player  peter = new Forwards("peter");
            peter.attack();
            Player mike = new Guards("mike");
            mike.attack();
            
            Player zhangsan = new Center("张三");
            zhangsan.attack();
            zhangsan.defense();
        }
    }

    输出结果:

    前锋:peter进攻
    后卫:mike进攻
    中锋:张三进攻
    中锋:张三防守

    球员“张三”不会说英语,需要翻译,用适配器模式完善代码

    //外籍中锋
    public class ForeignCenter {
        private String name;
        //外籍中锋只懂得中文“进攻”
        public void jingong() {
            System.out.println("中锋:"+name+"进攻");
        }
        //外籍中锋只懂得中文“防守”
        public void fangshou() {
            System.out.println("中锋:"+name+"防守");
        }
    
        //省略getter、setter方法
    }
    //翻译者
    public class Translator extends Player {
        //声明并实例化一个内部“外籍中锋”对象,表面翻译者与外籍球员有关联
        private ForeignCenter wjzf = new ForeignCenter();
        
        public Translator(String name) {
            super(name);
            wjzf.setName(name);
        }
        
        @Override
        public void attack() {
            //翻译者将attack翻译为jingong  告诉外籍中锋
            wjzf.jingong();
        }
    
        @Override
        public void defense() {
            //翻译者将defense翻译为fangshou  告诉外籍中锋
            wjzf.fangshou();
        }
    }

    main方法修改代码如下:

    public class Test {
        public static void main(String[] args) {
            Player  peter = new Forwards("peter");
            peter.attack();
            Player mike = new Guards("mike");
            mike.attack();
            //翻译者告诉张三,教练让你既要“进攻”又要“防守”
            Player zhangsan = new Translator("张三");
            zhangsan.attack();
            zhangsan.defense();
        }
    }

    现在就算是张三不懂英文,教练不懂中文,但因为有了翻译者,团队沟通合作成为了可能。

    如果能事先预防接口不同的问题,不匹配问题就不会发生:在有小的接口不统一问题发生时,及时重构,问题不至于扩大:只有碰到无法改变原有设计和代码的情况时,才考虑适配。

    事后控制不如事中控制,事中控制不如事前控制。

  • 相关阅读:
    使用 libevent 和 libev 提高网络应用性能
    在PHP中PDO解决中文乱码问题的一些补充
    apache重写规则详解
    Apache的配置
    正则表达式30分钟入门教程
    LVS+keepalived搭建负载均衡
    php判断终端是手机还是电脑访问网站代码
    nginx 502 bad gateway
    算法复习-深度优先遍历和回溯法的关系
    分支限界法和回溯法对比
  • 原文地址:https://www.cnblogs.com/jwen1994/p/10164371.html
Copyright © 2011-2022 走看看