首页 > 其他分享 >适配器模式

适配器模式

时间:2024-01-17 15:26:15浏览次数:25  
标签:适配器 接口 public 模式 播放 void Mp3

  • 定义:将一个类的接口转换成客户期望的另一个接口,使原本接口不兼容的类可以一起工作
  • 类型:结构型
  • 适用场景:
    •   已经存在的类,它的方法和需求不匹配时(方法结果相同或相似)
    •   不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案
  • 优点:
    •   能提高类的透明性和复用,现有的类复用但不需要改变,解决了现有类和目标类不匹配的问题
    •   目标类和适配器类解耦,提高程序扩展性
    •   符合开闭原则,具体的实现都在适配器中,客户端知道的只有适配器类,扩展也只需要扩展适配器类即可
  • 缺点:
    •   适配器编写过程需要全面考虑,可能会增加系统的复杂性
    •   增加系统代码可读的难度
  • 扩展:
    •   对象适配器:符合组合复用原则,使用委托机制
    •   类适配器:通过类继承来实现
  • 相关设计模式:
    •   适配器模式和外观模式:都是对现有类,现有系统的封装,外观定义了新的接口,而适配器则是复用原有的接口,适配器是两个已有的接口协同工作,而外观则是在现有的系统中提供一个更为方便的访问入口,外观模式是适配整个子系统,所以外观针对的对象力度更大
    •   适配器模式和装饰者模式:装饰者模式重点在于增强,适配器模式重点在于适配

播放器接口及实现coding

/**
 * <p>播放器接口 </p>
 */
public interface IPlayer {

    /**
     * 播放MV
     */
    void playMVs();

    /**
     * 播放音乐 == 与Mp3播放音乐的功能【方法】名称一致
     */
    void playMusics();

    /**
     * 播放电影
     */
    void playMovies();

}

/**
 * <p>MP3播放器  == 功能单一,只播放歌曲</p>
 */
public class Mp3 {

    private String name = "";

    public Mp3() {
    }

    public Mp3(String name) {
        this.name = name;
    }

    /**
     * 播放歌曲 == 凡是能播放音乐的设备,都要适配Mp3类的这个方法
     * 如果你说鼠标能播放歌曲,Ok,也不是做不到,哈哈
     */
    public void playMusics() {
        System.out.println("Mp3 -- " + this.name + "播放歌曲");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

类适配器coding

/**
 * <p>
 *     适配器 == QQ播放器,将Mp3播放音乐的功能直接"窃取"到QQ播放器里
 *     即QQ播放器无需再实现播放接口中的播放音乐的功能了
 * </p>
 */
public class QQPlayer extends Mp3 implements IPlayer {

   @Override
   public void playMVs() {
      System.out.println("QQ播放器实现播放MV功能");   
super.playMVs();
   }
   
   @Override
   public void playMovies() {
      System.out.println("QQ播放器实现播放电影功能");
super.playMovies();         
   }

}

UML

对象适配器coding

/**
 * <p>适配器 == 暴风音影播放器,将Mp3播放音乐的功能直接扩展到播放器里,即无需再实现播放器播放音乐的功能了</p>
 */
public class BaoFengPlayer implements IPlayer {

    /**
     * 唯一不同于QQ适配器的地方就是,暴风适配器里面可以创建Mp3的实例
     * 即可以实现不同原对象播放音乐的方法,无需再继承Mp3类
     */
    private Mp3 mp3;

    public BaoFengPlayer(Mp3 mp3) {
        this.mp3 = mp3;
    }

    @Override
    public void playMVs() {
        System.out.println("暴风影音实现播放MV功能");
    }

    @Override
    public void playMusics() {
        this.mp3.playMusics();
    }

    @Override
    public void playMovies() {
        System.out.println("暴风影音实现播放电影功能");
    }

    public Mp3 getMp3() {
        return mp3;
    }

    public void setMp3(Mp3 mp3) {
        this.mp3 = mp3;
    }

}

UML

接口适配器

/**
 * <p>
 *     1、播放器抽象类 == 实现播放接口
 *     2、抽象类中的非抽象方法:子类按需实现
 *     3、抽象类中的抽象方法:子类必须全部实现
 *     4、接口中的方法:实现类必须全部实现
 * </p>
 */
public abstract class AbstractPlayer implements IPlayer {

    /**
     * 播放MV
     */
    @Override
    public void playMVs() {
    }

    /**
     * 播放音乐
     */
    @Override
    public void playMusics() {
    }

    /**
     * 播放电影
     */
    @Override
    public void playMovies() {
    }

    /**
     * 播放器功能展示抽象方法,子类中必须实现
     */
    public abstract void show();
}
/**
 * <p>播放器A  == 只具有播放歌曲的功能</p>
*/
public class APlayer extends AbstractPlayer{

   /**
    * 重写父类方法
    */
   @Override
   public void playMusics() {
      System.out.println("A实现播放音乐的功能");
   }

   @Override
   public void show(){
      System.out.println("=====播放器A功能展示:");
      playMusics();
      playMVs();
      playMovies();
   }
}
/**
 * <p>播放器B  == 只具有播放MV的功能</p>
 */
public class BPlayer extends AbstractPlayer{

   /**
    * 重写父类方法
    */
   @Override
   public void playMVs() {
      System.out.println("B实现播放MV的功能");
   }

   @Override
   public void show(){
      System.out.println("=====播放器B功能展示:");
      playMusics();
      playMVs();
      playMovies();
   }
/**
 * <p>播放器C == 即能播放音乐、MV、又能播放电影</p>
 */
public class CPlayer extends AbstractPlayer{

   /**
    * 重写父类播放MV方法
    */
   @Override
   public void playMVs() {
      System.out.println("C实现播放MV的功能");
   }
   

   @Override
   public void playMusics() {
      System.out.println("C实现播放音乐的功能");
   }


   @Override
   public void playMovies() {
      System.out.println("C实现播放电影的功能");
   }


   @Override
   public void show(){
      System.out.println("=====播放器C功能展示:");
      playMusics();
      playMVs();
      playMovies();
   }
}

UML

测试

/**
 * <p>适配器模式测试 </p>
 */
public class AdapterTest {

   public static void main(String[] args){
      
      // 使用类适配器
      useAdapterOfClass();   
      
      // 使用对象适配器
      useAdapterOfObject();  
      
      // 使用接口适配器
      useAdapterOfInterFace();
      
      /**
       * 类适配器:当一个类A想拥有某个接口I里的所有功能时,却又懒得实现接口中的M方法时
       *        则可以专门定义一个类B,B中的方法和接口I中的M方法保持一致,只不过B中的M方法已经通过定制进行了功能实现
       *        这时候,我们称B是一个待适配的类,而B中的M方法我们称原方法,接口I中的M方法称作目标方法
       *        A类我们则称呼为真正要适配的类,这个类通过继承B类、实现接口I即可具有目标接口I中的所有功能
       *        正如一开始说的,适配的类A,懒得实现接口I中的M方法,怎么办,那我们就专门给A开个小灶,交给B类来做就好了
       * 
       * 对象适配器:其实和类适配器差不多,唯一的区别就是,类适配器无法对B类进行实例化,不够灵活,而对象适配器中
       *         则将B类的实例放在了真正适配的类中,不管是内部还是外部,都可以实例化B对象,实现不同B对象的原始方法
       *       
       * 接口适配器:类适配和对象适配器有个不好的地方就是,适配器对象必须实现接口I中的所有功能
       *         但现实是,我有时候不太想要I中的某些功能,怎么办?
       *         比如A对象只实现I中的M方法,B对象只实现I中的N方法,而C对象则全部实现I中的M、N、P方法
       *         这时候就需要借助抽象类Ab了,Ab实现接口I,抽象类和接口的区别就是,抽象类中的方法无需都实现,
       *         而接口中的方法必须全部实现,这样一来,我们适配的类就可以通过只继承Ab类来实现接口I中的部分功能了
       *         
       * 项目中,具体用到哪种模式的适配器,可以好好斟酌一下了,其实我在项目中用到最多的是接口适配器模式
       *   
       */
      
   }

   private static void useAdapterOfClass() {
      // 类适配器模式测试 == 持有类Mp3的原始方法,但是不能创建该类的实例
      IPlayer qqPlayer = new QQPlayer();
      qqPlayer.playMusics();
      qqPlayer.playMVs();
      qqPlayer.playMovies(); 
      System.out.println("============分割线");
   }
   
   private static void useAdapterOfObject() {
      // 对象适配器模式测试 == 持有类Mp3的原始方法,但是可以创建不同的Mp3类的实例
      Mp3 sonyMp3 = new Mp3("索尼(SONY) NW-ZX300A");
      IPlayer bfPlayer = new BaoFengPlayer(sonyMp3);
      bfPlayer.playMusics();
      bfPlayer.playMVs();
      bfPlayer.playMovies();    
      System.out.println("=========暴风影音升级");
   
      // 暴风音影升级,改用纽曼的Mp3播放音乐功能
      Mp3 newsMyMp3 = new Mp3("纽曼(Newsmy)F35");
      ((BaoFengPlayer)bfPlayer).setMp3(newsMyMp3);
      bfPlayer.playMusics();
      bfPlayer.playMVs();
      bfPlayer.playMovies();
      System.out.println("============分割线");
   }
   
   private static void useAdapterOfInterFace() {
      // 接口适配模式测试 == 适配类无需实现接口里面的所有方法,这时候需要借助一个抽象类进行一下过度
      AbstractPlayer aPlayer = new APlayer();
      aPlayer.show();
      
      AbstractPlayer bPlayer = new BPlayer();
      bPlayer.show();
      
      AbstractPlayer cPlayer = new CPlayer();
      cPlayer.show();
   }
}

实际场景

  • 场景描述:将200V的交流电适配成5V的直流电用于给手机充电
  • Coding:

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();
    }
}

打印结果

输出交流电220V

使用PowerAdapter输入AC:220V输出DC:5V

源码中应用

  • javax.xml.bind.annotation.adapters.XmlAdapter

IMG_256

  • org.springframework.aop.framework.adapter.AdvisorAdapter:Spring 源码中 AOP 相关的适配器,可以看到它的一个实现
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
    MethodBeforeAdviceAdapter() {
    }

    public boolean supportsAdvice(Advice advice) {
        return advice instanceof MethodBeforeAdvice;
    }

    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice)advisor.getAdvice();
        return new MethodBeforeAdviceInterceptor(advice);
    }
}

 

标签:适配器,接口,public,模式,播放,void,Mp3
From: https://www.cnblogs.com/wangzhilei-src/p/17970035

相关文章

  • 华企盾DSC防泄密系统四种加密模式的应用场景
    在当今数字化的时代,企业的核心竞争力往往体现在数据资产上,而数据安全的重要性也日益凸显。数据加密是保护企业核心数据的重要手段,不同的加密模式适用于不同部门与员工,能够更好地平衡数据安全与工作效率。本文将围绕华企盾DSC数据防泄密系统介绍四种加密模式,包括使用场景、好处和可......
  • JavaGuide 设计模式
    JavaGuide设计模式1.软件设计原则设计原则名称简单定义开闭原则对扩展开放,对修改关闭单一职责原则一个类只负责一个功能领域中的相应职责里氏替换原则所有引用基类的地方必须能透明地使用其子类的对象依赖倒置原则依赖于抽象,不能依赖于具体实现接......
  • 模拟适配器设计方案:360-基于10G以太网的模拟适配器
     基于10G以太网的模拟适配器一、产品概述   基于10G以太网的模拟适配器是一款分布式高速数据采集系统,实现多路AD的数据采集,并通过10G以太网光纤远距离传输到存储计算服务器,计算控制指令能通过光纤返回给数据卡进行IO信号控制。产品基于10G太网络,可迅......
  • 2023苹果商务管理模式分发app完全指南
    原文链接https://blog.csdn.net/yichensheng/article/details/130622006 随着苹果对企业级开发证书的管控越来越严格,越来越多的企业级证书到期后,苹果不再予以续约,但是很多app都有企业内部分发需求,不希望自己的应用被公开上架。这时候,我们可以参考苹果官方的建议,使用商务管理模......
  • Java动态代理、AOP和装饰器模式
    面向切面编程AOP-AspectOrientedPrograming,主要用于处理核心业务逻辑外的一些东西,比如日志和缓存。这个“切面”可以理解为在代码的某个地方切一刀,在其中加一些东西。装饰器以日志为例,如果没有使用AOP,那么可以使用装饰来实现类似的代码。我们使用装饰器模式来实现一下在执行......
  • 简单的.NET 8 Web API使用Kafka 发布订阅模式,示例api示例
    简单的.NET8WebAPI使用Kafka发布订阅模式,示例api示例kafka当使用Kafka时,我们需要使用Kafka的客户端库来与Kafka集群进行通信。在.NETCore中,可以使用Confluent.Kafka客户端库来实现与Kafka的集成。首先,我们需要在项目中添加Confluent.Kafka库的引用。首先,使用NuGet包管......
  • Spring Boot 整合工厂设计模式完成服务调用的一种实现
    工厂模式是一种创建型设计模式,其主要目的是提供一个创建对象的接口,但将具体类的实例化延迟到子类中。这样,客户端代码就不需要知道要实例化的具体类,只需要知道使用的工厂接口。项目结构如下代码实例如下所有水果都要实现这个接口publicinterfaceAllFruits{voideatFru......
  • 装饰者模式
    增强原有对象,而不改变原有对象定义:在不改变原有对象的基础上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象功能)类型:结构型适用场景:扩展一个类的功能或给一个类添加附加职责动态的给一个对象添加功能,这些功能可以再动态的撤销优点:继承的......
  • Java 实现单例模式
    目录单例模式简介双重检查锁优缺点延迟加载模式(Initialization-on-demandholderidiom)优缺点饿汉模式优缺点枚举方式优缺点单例模式简介单例模式是一种创建型设计模式,让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点。单例模式保证了系统内存中该类只存在一......
  • Solo开发者社区-重新思考云原生应用的开发模式
    当前云原生应用的开发模式在FaaS环境下存在挑战,本文提出一种开发模式构想:“单体式编程,编译时拆分,分布式执行”,旨在简化云应用开发,提升开发效率和应用性能。思路是通过编译器自动拆分单体应用代码,实现云基础设施上的分布式运行。(Solo社区投稿)背景云原生应用通常形象地解释为......