zoukankan      html  css  js  c++  java
  • 适配器模式(Adapter)---结构型

    1 基础知识

    定义:将一个类的接口(被适配者)转换成客户期望的另一个接口(目标)。特征:使原本接口不兼容的类可以一起工作。

    本质:转换匹配,复用功能。把不兼容的接口转换为客户端期望的样子从而实现功能的复用。

    使用场景:已经存在的类,它的方法(接口)和需求不匹配时的解决方案。注意适配器模式不是软件设计阶段需要考虑的设计模式,而是随着软件维护,由于不同产品不同厂家造成功能类似而接口不相同情况下的解决方案。

    优点:

    更好的复用:性如果功能是已经有了的,只是接口不兼容,那么通过适配器模式就可以让这些功能得到更好的复用。

    更好的可扩展性:在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。

    缺点:过多地使用适配器,会让系统非常零乱,不容易整体进行把握比如,明明看到调用的是A接口,其实内部被适配成了B接口来实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

     2 代码示例

    适配器的两种实现方式:

    类适配器:

    被适配者类:Adaptee

    public class Adaptee {
        public void adapteeRequest(){
            System.out.println("被适配者的方法");
        }
    
    }

    目标接口:Target

    public interface Target {
        void request();
    }

    目标实现:

    public class ConcreteTarget implements Target {
        @Override
        public void request() {
            System.out.println("concreteTarget目标方法");
        }
    }

    适配者类:Adapter  通过继承和实现将被适配者类和目标联系在了一起

    public class Adapter extends Adaptee implements Target{
        @Override
        public void request() {
            
            //在此方法体内可以添加需要的代码
            
            super.adapteeRequest();
        }
    }

    应用层:

    public class Test {
        public static void main(String[] args) {
            Target target = new ConcreteTarget();
            //目标方法输出
            target.request();
    
            Target adapterTarget = new Adapter();
            //适配者方法输出
            adapterTarget.request();
        }
    }

    其类图关系如下:

    对象适配器:

    修改适配者类:

    public class Adapter implements Target{
        //通过组合方式而不是继承
        private Adaptee adaptee = new Adaptee();
    
        @Override
        public void request() {
    
            //添加自己需要代码
    
            adaptee.adapteeRequest();
        }
    }

    应用层代码不变直接测试即可,其类关系图如下图,在代码中有一个原则如果继承和组合都可以满足要求优先选择组合。

    场景使用:生活中的手机充电,需要把220V转换为5V电源。

     220V电源:被适配者

    public class AC220 {
        public int outputAC220V(){
            int output = 220;
            System.out.println("输出交流电"+output+"V");
            return output;
        }
    }

    目标接口:5V电源

    public interface DC5 {
        int outputDC5V();
    }

    适配者:

    public class PowerAdapter implements DC5{
        private AC220 ac220 = new AC220();
    
        @Override
        public int outputDC5V() {
            int adapterInput = ac220.outputAC220V();
            //变压器...
            int adapterOutput = adapterInput/44;
    
            System.out.println("使用PowerAdapter输入AC:"+adapterInput+"V"+"输出DC:"+adapterOutput+"V");
            return adapterOutput;
        }
    }

    应用层:

    public class Test {
        public static void main(String[] args) {
            DC5 dc5 = new PowerAdapter();
            dc5.outputDC5V();
        }
    }

    在实际开发中场景:如一个日志记录系统最初的的版本1:LogMode1 只有两个简单的功能以文件的形式读日志和写日志。

    public interface LogMode1 {
        public void writeLogFile();
        public void readLogFile();
    }

    随着使用升级系统便有了版本2:将日志保存到数据库中可以对其进行增删改查

    public interface LogMode12 {
        //新增日志
        public void creatLogFile();
        //修改日志
        public void updateLogFile();
        //删除日志
        public void removeLogFile();
        //获取所有日志
        public List<LogFile> getLogFile();
    }

    此时客户端提出需求,能否让版本2同时支持数据库存储和文件存储?直接的思路是进行合并但是有问题,现在客户端操作的第二版的日志接口,但第一版的接口与第二版的不同,客户端无法以同样的方式使用第一版的实现,如下图所示:

     简单粗暴的方法是在第二版中增加文件存储功能,但是这些功能在第一版中已经实现过了,因此要避免重复劳动。解决方法就是采用适配器模式:Target接口相当于第二版的日志接口,被适配者则是第一版接口,采用类似前面提供的代码即可解决。

    3 源代码中的使用

    4 相关设计模式

    (1)适配器模式与桥接模式

    其实这两个模式除了结构略为相似外,功能上完全不同。适配器模式是把两个或者多个接口的功能进行转换匹配;而桥接模式是让接口和实现部分相分离,以便它们可以相对独立地变化。

    (2)适配器模式与装饰模式

    从某种意义上讲,适配器模式能模拟实现简单的装饰模式的功能,也就是为已有功能增添新功能,因为在适配器里可以添加功能。但仅仅是类似,造成这种类似的原因是:两种设计模式在实现上都是使意用的对象组合,都可以在转调组合对象的功能前后进行一些附加的处理,因此有这么一个相似性。它们的目的和本质都是不一样的。两个模式有一个很大的不同:一般适配器适配过后是需要改变接口的,如果不改接口就没有必要适配了;而装饰模式是不改变接口的,无论多少层装饰都是一个接口。因此装饰模式可以很容易地支持递归组合,而适配器就做不到,每次的接口不同,无法递归。

    (3)适配器模式和代模式

    适配器模式可以和代理模式组合使用。在实现近配器的时候,可以通过代理来调用 Adaptee,这样可以获得更大的灵活性。

    (4)适配器模式和抽象工厂模式。

    在适配器实现的时候,通常需要得到被适配的对象。如果被适配的是一个接口,那么就可以结合一些可以创造对象实例的设计模式,来得到被适配的对象示例,比如抽象工厂模式、单例模式、工厂方法模式等。

    0

  • 相关阅读:
    数据库设计主键定义思考
    dotnet(C#)的面试题,大家共享一下
    一些有创意的SQL语句
    asp.net(c#) 服务器探针
    存储过程共有三种返回值
    如何删除表中的重复记录?等等常用SQL语句的积累
    一般存储过程示例
    关于utf8,unicode字符集
    在Asp.net里利用DIV层元素弹出窗体
    数据库主键设计思考
  • 原文地址:https://www.cnblogs.com/youngao/p/11350104.html
Copyright © 2011-2022 走看看