适配器模式

将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,适配器模式分为类结构型模式(继承)和对象结构型模式(组合)两种,前者(继承)类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

别名也可以是Wrapper,包装器

比如有已经定义好的A 和B两个类,之前两个类之间并没有任何关联和交互,此时突然想在A中的某个方法a()调用B中的方法,我们不应该直接在a()方法中添加,这样违反了开闭原则。我们可以创建一个新的适配器类来连接两个类。

适配器模式(Adapter)包含以下主要角色。
目标(Target)接口:可以是抽象类或接口。客户希望直接用的接口
适配者(Adaptee)类:隐藏的转换接口
适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口。

实例:字幕翻译功能

可以进行电影的播放并返回中文字幕。但是现在有日本人想看这个电影,我们又有一个翻译的类,在不改变原播放器类的基础上,我们可以新建一个适配器类组合/继承翻译类,让日本人调用适配器类来观看电影

原类结构

  1. /**
  2. * 1、系统原有的接口,可以播放电影,并且返回字幕
  3. */
  4. public interface Player {
  5. public String play(); //电影播放功能
  6. }
  1. /**
  2. * 2、系统原有的接口,可以翻译并返回翻译后的内容
  3. */
  4. public interface Translate {
  5. public String translate(String str);
  6. }
  1. /*
  2. *系统原有实现类,播放电影并返回字幕
  3. */
  4. public class MoviePlayer implements Player{
  5. @Override
  6. public String play() {
  7. System.out.println("电影名: 小时代");
  8. String str="你好";//第一行字幕并返回
  9. return str;
  10. }
  11. }
  1. /**
  2. * 系统原有实现类,可以将中文转换成日文
  3. */
  4. public class Zh_JPTranslator implements Translator {
  5. @Override
  6. public String translate(String str) {
  7. if ("你好".equals(str)){
  8. return "库你急哇";
  9. }
  10. if ("什么".equals(str)){
  11. return "纳尼";
  12. }
  13. return "*********";
  14. }
  15. }
  1. 通过类结构模式(继承的方式)
  1. public class JpMoviePlayerAdapter extends Zh_JPTranslator implements Player {
  2. private Player player;
  3. public JpMoviePlayerAdapter(Player player){
  4. this.player=player;
  5. }
  6. @Override
  7. public String play() {
  8. String content= player.play();
  9. String translate = translate(content);
  10. return translate;
  11. }
  12. }
  1. public class MainTest {
  2. public static void main(String[] args) {
  3. //日本人想看这个电影
  4. JpMoviePlayerAdapter adapter=new JpMoviePlayerAdapter(new MoviePlayer());
  5. adapter.play();
  6. }
  7. }

2.通过对象结构型模式(组合的方式)

  1. public class JpMoviePlayerAdapter implements Player {
  2. private Player player;
  3. private Translator translator=new Zh_JPTranslator(); //这里直接new了出来,可以通过构造函数传也行
  4. public JpMoviePlayerAdapter(Player player){
  5. this.player=player;
  6. }
  7. @Override
  8. public String play() {
  9. String content= player.play();
  10. String translate = translator.translate(content);
  11. System.out.println(translate);
  12. return translate;
  13. }
  14. }

实现适配器的两种方式

  1. 类结构模式(继承)

结构型-适配器&装饰器 - 图1

  1. 对象结构模式(组合)

结构型-适配器&装饰器 - 图2

使用场景

什么场景用到?
Tomcat如何将Request流转为标准Request;
tomcat.Request接口
servlet.Request接口
tomcat === CoyoteAdapte === ServletRequest
Spring AOP中的AdvisorAdapter是什么:增强的适配器
前置、后置、返回、结束 Advisor(通知方法)
底层真的目标方法
Spring MVC中经典的HandlerAdapter是什么;
HelloController.hello() 本身存在的
HandlerAdapter 通过这个适配器,调用下面Servlet中的方法
Servlet.doGet() 本身存在的
SpringBoot 中 WebMvcConfigurerAdapter为什么存在又取消
……

装饰器模式

某个类有一天功能不够用了,想在这个类的上重新增强一样,同样我们不能修改原类中的方法(开闭原则),我们创建一个新的增强类(Wrapper/decorator,适配器也可以叫Wrapper)然后在这个类上进行增强。

装饰器和适配器很像,只不过装饰器是创建了一个类,直接在类中自己对方法增强,而适配器相当于连接两个类,一个类写好的方法可以作用在另一个类上

实例 直播增强

  1. //抖音直播接口
  2. public interface ManTikTok {
  3. void tiktok();
  4. }
  1. //实现类
  2. public class LeiFengYangTikTok implements ManTikTok{
  3. @Override
  4. public void tiktok() {
  5. System.out.println("雷丰阳正在直播....");
  6. }
  7. }
  1. //装饰器接口,专门增强ManTikTok接口的类
  2. public interface TikeTokDecorator extends ManTikTok{ //因为需要原方法,在此继承并提供自己的增强方法,在适配器中不需要增强方法,因为在另一个类已经写好了,所以适配器中不用提供这个接口也可以
  3. void enable();//提供增强的方法
  4. }
  1. public class MeiYanDecorator implements TikeTokDecorator{
  2. //被装饰的对象
  3. private ManTikTok manTikTok;
  4. public MeiYanDecorator(ManTikTok manTikTok){
  5. this.manTikTok=manTikTok;
  6. }
  7. @Override
  8. public void tiktok() {
  9. enable(); //开启直播前先开启美颜
  10. manTikTok.tiktok();
  11. }
  12. /**
  13. * 定义增强功能,装饰器就是在类里直接写,而适配器已经有写好了的,可以直接引入用
  14. */
  15. @Override
  16. public void enable() {
  17. System.out.println("开启了美颜...");
  18. }
  19. }

使用场景

抽象构件(Component)角色:
定义一个抽象接口以规范准备接收附加责任的对象。
具体构件(ConcreteComponent)角色:
实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰(Decorator)角色:
继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
具体装饰(ConcreteDecorator)角色:
实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。