场景介绍: (1)假设我们做了一个第一版的一个系统,这个系统里有一个接口和一个实现类 (2)接着我们开始做第二版的系统,这个系统我们定义了一个新的接口,和新的实现类 (3)但是我们同时在第二版的系统中,也要使用第一版系统中定义的那个老接口和老实现类

1.常规

  1. package com.example.demo.pattern.adapter;
  2. /**
  3. * @author chenchao
  4. * @date 2021/11/8
  5. */
  6. public class WithoutAdapterPatternDemo {
  7. public static void main(String[] args) {
  8. OldInterface oldObject = new OldInterfaceImpl();
  9. NewInterface newObject = new NewInterfaceImpl();
  10. oldObject.oldExecute();
  11. newObject.newExecute();
  12. // 如果不用任何设计模式,我们的问题在哪儿?
  13. // 问题其实很明显,就是说,我们的新的代码中,融合了新老两套接口,很麻烦的一个事情
  14. // 首先如果你这么干的话,就会导致代码很恶心,面向的是规范和风格完全不同的两套接口,你理解和维护的成本提高了
  15. // 其次,假如说,现在都不给你选择使用老版本接口的机会
  16. // 直接强制性公司规范要求按照新版本接口来走,你的老版本接口的实现类,就没法用了啊?
  17. // 难不成还要基于新版本的接口重新写一套?
  18. }
  19. /**
  20. * 老版本接口
  21. * @author chenchao
  22. *
  23. */
  24. public static interface OldInterface {
  25. void oldExecute();
  26. }
  27. /**
  28. * 老版本接口的实现类
  29. * @author chenchao
  30. *
  31. */
  32. public static class OldInterfaceImpl implements OldInterface {
  33. @Override
  34. public void oldExecute() {
  35. System.out.println("老版本接口实现的功能逻辑");
  36. }
  37. }
  38. /**
  39. * 新版本接口
  40. * @author chenchao
  41. *
  42. */
  43. public static interface NewInterface {
  44. void newExecute();
  45. }
  46. /**
  47. * 新版本接口的实现类
  48. * @author chenchao
  49. *
  50. */
  51. public static class NewInterfaceImpl implements NewInterface {
  52. @Override
  53. public void newExecute() {
  54. System.out.println("新版本接口实现的功能逻辑");
  55. }
  56. }
  57. }

2.适配器模式

  1. package com.example.demo.pattern.adapter;
  2. /**
  3. * @author chenchao
  4. * @date 2021/11/8
  5. */
  6. public class AdapterPatterDemo {
  7. public static void main(String[] args) {
  8. NewInterface oldObject = new NewInterfaceAdapter(new OldInterfaceImpl());
  9. NewInterface newObject = new NewInterfaceImpl();
  10. oldObject.newExecute();
  11. newObject.newExecute();
  12. // 适配器模式
  13. // 就是你手上有新老俩接口和一个老接口的实现类
  14. // 但是现在系统中要面向新接口来开发,老接口的实现类就不能直接用了,不能直接面向老接口来开发
  15. // 开发一个老接口到新接口的一个适配器
  16. // 适配器是实现了新接口的,但是适配器中持有老接口实现类实例的引用
  17. // 适配器的新接口方法的实现,全部基于老接口实现类的老方法来实现即可
  18. // 对于调用方而言,只要使用适配器来开发即可,就可以通过面向新接口开发,底层使用老接口实现类
  19. }
  20. /**
  21. * 老版本接口
  22. *
  23. * @author chenchao
  24. */
  25. public static interface OldInterface {
  26. void oldExecute();
  27. }
  28. /**
  29. * 新版本接口
  30. *
  31. * @author chenchao
  32. */
  33. public interface NewInterface {
  34. void newExecute();
  35. }
  36. /**
  37. * 定义一个适配器类
  38. *
  39. * @author chenchao
  40. */
  41. public static class NewInterfaceAdapter implements NewInterface {
  42. private OldInterface oldObject;
  43. public NewInterfaceAdapter(OldInterface oldObject) {
  44. this.oldObject = oldObject;
  45. }
  46. @Override
  47. public void newExecute() {
  48. oldObject.oldExecute();
  49. }
  50. }
  51. /**
  52. * 老版本接口的实现类
  53. *
  54. * @author chenchao
  55. */
  56. public static class OldInterfaceImpl implements OldInterface {
  57. @Override
  58. public void oldExecute() {
  59. System.out.println("老版本接口实现的功能逻辑");
  60. }
  61. }
  62. /**
  63. * 新版本接口的实现类
  64. *
  65. * @author chenchao
  66. */
  67. public static class NewInterfaceImpl implements NewInterface {
  68. @Override
  69. public void newExecute() {
  70. System.out.println("新版本接口实现的功能逻辑");
  71. }
  72. }
  73. }

3.好处

这个模式一般是在系统不断升级的过程中使用,对已经写好的老的类,写一套适配器来适配老类,但是提供新的接口,这个我们在后面系统升级的时候,可以去实践。在项目阶段二的时候,会去实践的,真的有版本升级的时候,才可以完美的去演示这个模式的使用效果。

还有一种情况,是对于已有的第三方类库,比如redis的客户端,或者是elasticsearch的客户端,他们提供了一套API,但是我们这里的要求是需要面向我们这里的DAO接口来进行编程,此时可以写一个适配器,将比如redis客户端的接口适配到我们的接口,这个我们会在本次课程来实践。

比如我们的DAO接口,要求的接口风格都是:save、update、remove、list、get,这些方法风格

DAORedisImpl,redis客户端,get、set、mset、mget,一套接口;适配器,DAORedisImpl就是一个适配器,这个适配器实现的是我们的DAO接口,在我们的save、update、remove等方法中,去调用redis客户端的get、set、mset、mget等方法。