• 设计模式详解——适配器模式


    前言

    今天我们来看另一个和包装有关的设计模式——适配器模式,和装饰者模式比起来,它更像是一位无名耕耘者,隐身于沟渠之中,干着脏活累活——转换接口。用时下比较火的一个词来比喻这种设计模式的话,那就是女装大佬,这真的是适配器模式最佳类比了,我相信你看完今天的所有内容,一定会明白的

    适配器模式

    适配器模式将一个类的接口,转换成客户期望的另一个接口,适配器让原本不兼容的接口可以合作无间。

    适配器模式采用的设计原则是使用对象组件,以修改的接口包装被适配者,这样的好处是,被适配者的任何子类,都可以搭配适配器使用。

    采用适配器模式之后:

    要点

    • 适配器模式主要是为了在不改变原有接口的基础上,适配客户新的接口
    • 当需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器模式
    • 适配器有两种形式:对象适配器和类适配器。类适配器需要用到多重继承
    • 适配器将一个对象包装起来以改变起接口;装饰者将一个对象包装起来以增加新的行为和属性;而外观模式将一群对象“包装”起来以简化其接口

    示例代码

    从网上搜了一些适配器的示例,但是最后发现还是没有《Head First设计模式》中的简单,所以最后我还是用了书上的示例。

    示例的场景是这样的:假设客户需要一只鸭子,但是我们手里只有火鸡,这时候为了满足客户的需求,我们必须通过适配器将火鸡转换成鸭子。

    下面就是整个实现过程:

    原始系统接口

    首选我们拿到鸭子的接口,其中有两个方法,要给是鸣叫,一个是飞

    public interface Duck {
        void quack();
        void fly();
    }
    
    接口实现类

    这个是鸭子的实现,这是仅仅是为了后期测试。因为我们现在没有这个实现,所以后面要适配这样一个对象。

    public class MallardDuck implements Duck {
        @Override
        public void quack() {
            System.out.println("quack");
        }
    
        @Override
        public void fly() {
            System.out.println("I'm flying");
        }
    }
    
    被适配对象接口

    这个是我们火鸡的原始接口,也就是我们要适配成鸭子的火鸡的基类,也有两个方法,一个是鸣叫,一个是飞。

    public interface Turkey {
        void gobble();
        void fly();
    }
    

    火鸡的实现类:

    public class WildTurkey implements Turkey {
        @Override
        public void gobble() {
            System.out.println("gobble gobble");
        }
    
        @Override
        public void fly() {
            System.out.println("I'm flying a short distance");
        }
    }
    
    适配器实现

    这里就是火鸡适配鸭子的适配器,首先它要实现鸭子的接口,然后我们定义一个火鸡属性,用于接收我们的火鸡实例,再然后我们将火鸡的鸣叫和飞的方法分别封装到鸭子的对应方法,因为要是一直飞,火鸡是普鲁普鲁飞,所以要多次飞。至此 ,火鸡适配鸭子的适配操作就完成了,下面我们测试下。

    public class TurkeyAdapter implements Duck {
        Turkey turkey;
    
        public TurkeyAdapter(Turkey turkey) {
            this.turkey = turkey;
        }
    
        @Override
        public void quack() {
            turkey.gobble();
        }
    
        @Override
        public void fly() {
            for (int i = 0; i < 5; i++) {
                turkey.fly();
            }
        }
    }
    
    测试代码

    这里我们分别创建了鸭子、火鸡和适配了鸭子的火鸡的示例,演示他们的执行过程:

     @Test
        public void testDuck() {
            MallardDuck duck = new MallardDuck();
    
            WildTurkey turkey = new WildTurkey();
            TurkeyAdapter turkeyAdapter = new TurkeyAdapter(turkey);
            System.out.println("火鸡:");
            turkey.gobble();
            turkey.fly();
    
            System.out.println("=============\n绿头鸭:");
            duck.quack();
            duck.fly();
    
            System.out.println("=============\n火鸡适配的鸭子:");
            turkeyAdapter.quack();
            turkeyAdapter.fly();
        }
    

    从代码中我们可以看到,这里适配了鸭子的火鸡像鸭子一样执行了quackfly操作

    运行结果:

    总结

    从上面的示例中,我们可以很清楚的看到,适配器模式本质上就是类型的转换,除了我们这里的例子,日常生活中还有很多类似的例子,比如电脑显示器VGAHDMI、用电设备插头转换等:

    虽然都是类型的包装和转换,但是适配器模式和装饰者模式是有本质区别的,装饰者模式始终是同同一种类型的包装和转换,也就是说所有的包装类于被包装类,本质上都是同一种类型,但是在适配器中,转换和包装的一定是不同的类型,比如火鸡到鸭子。

    最后引用一段话来结束今天的内容:

    如果它走起来像只鸭子,叫起来像只鸭子,那么它必定可能是一只鸭子包装了鸭子适配器的火鸡……

  • 相关阅读:
    C#全角半角转换输出解决方法
    screen命令
    Parrot Linux国内源
    screen命令在freebsd安装和使用
    sysbench0.5 在 centos7下安装 (mysql-community-server)
    Mysql中文乱码问题完美解决方案
    PHP返回数据被nginx截断问题的解决方法
    yii2笔记:asset压缩js,css文件
    Yii2笔记:activerecord和activecontroller
    yii2笔记: 模块(module)
  • 原文地址:https://www.cnblogs.com/caoleiCoding/p/15412916.html
Copyright © 2020-2023  润新知