设计模式学习笔记(五、结构型-适配器模式)

目录:

  • 什么是适配器模式
  • 为什么要有适配器模式
  • 如何实现适配器模式
  • 适配器模式的使用场景
  • 代理、桥接、装饰、适配器区别

什么是适配器模式

从语义上就能很明白的看出适配器模式是什么,它其实就是用来做适配的,把不兼容的接口转成成兼容的接口。

在生活中有一种东西非常贴合适配器模式,就是读卡器,它是用来兼容内存卡和USB接口。

为什么要有适配器模式

把不兼容的接口转成成兼容的接口

如何实现适配器模式

适配器的实现方式有两种:

1、类适配器:通过继承实现

1 public interface IAdapter {
2 
3     void func1();
4     void func2();
5     void func3();
6 }
 1 public class Adaptee {
 2 
 3     public void f1() {
 4     }
 5 
 6     public void f2() {
 7     }
 8 
 9     public void func3() {
10     }
11 }
 1 public class Adaptor extends Adaptee implements IAdapter {
 2     
 3     @Override
 4     public void func1() {
 5         super.f1();
 6     }
 7 
 8     @Override
 9     public void func2() {
10         // 重新实现fund2的逻辑
11     }
12 
13     // 这里fc()不需要实现,直接继承自Adaptee,这是跟对象适配器最大的不同点
14 }

2、对象适配器:通过组合实现

1 public interface IAdapter {
2 
3     void func1();
4     void func2();
5     void func3();
6 }
 1 public class Adaptee {
 2 
 3     public void f1() {
 4     }
 5 
 6     public void f2() {
 7     }
 8 
 9     public void func3() {
10     }
11 }
 1 public class Adaptor implements IAdapter {
 2 
 3     private Adaptee adaptee;
 4 
 5     public Adaptor(Adaptee adaptee) {
 6         this.adaptee = adaptee;
 7     }
 8 
 9     @Override
10     public void func1() {
11         // 委托给adaptee实现
12         adaptee.f1();
13     }
14 
15     @Override
16     public void func2() {
17         // 重写func2
18     }
19 
20     @Override
21     public void func3() {
22         // 委托给adaptee实现
23         adaptee.func3();
24     }
25 }

你这两种方式该如何选择呢,一看接口数量,二看契合度。

  • 如果接口数量不是很多,两个都可以。
  • 如果接口数量较多,且Adaptee与IAdapter中的接口相似度高(契合度),推荐使用类适配器的方式,这样Adaptor的代码更简洁。
  • 如果接口数量较多,但契合度不高,则推荐使用对适配器,因为基于组合的方式更加灵活。

适配器模式的使用场景

一般来说,适配器模式可以看作一种“补偿模式”,用来补救设计上的缺陷。

应用这种模式算是“无奈之举”。如果在设计初期,我们就能协调规避接口不兼容的问题,那这种模式就没有应用的机会了。

———————————————————————————————————————————————————————

1、封装有缺陷的接口设计

比如外部系统在设计上有缺陷(比如有大量静态方法、一个函数参数过多),而我们又不能改,那我们可以对其进行二次封装。———————————————————————————————————————————————————————

2、统一多个类的接口设计

假如你要对用户敏感词过滤,为了增加用户粘性,我们引入了多款第三方敏感词过滤系统,尽量的过滤多条敏感词。

但是,每个系统提供的过滤接口都是不同的。这就意味着我们没法复用一套逻辑来调用各个系统。

这个时候,我们就可以使用适配器模式,将所有系统的接口适配为统一的接口定义,这样我们可以复用调用敏感词过滤的代码。

 1 /**
 2  * A系统敏感词过滤
 3  *
 4  * @author zhoude
 5  * @date 2020/4/11 13:00
 6  */
 7 public class AThirdFilter {
 8 
 9     /**
10      * text是原始文本,函数输出用***替换敏感词之后的文本
11      */
12     public String filterSexyWords(String text) {
13         // 伪实现
14         return "***";
15     }
16 
17     public String filterPoliticalWords(String text) {
18         // 伪实现
19         return "+++";
20     }
21 }
 1 /**
 2  * B系统敏感词过滤
 3  *
 4  * @author zhoude
 5  * @date 2020/4/11 13:00
 6  */
 7 public class BThirdFilter {
 8 
 9     public String filter(String text) {
10         // 伪实现
11         return "***";
12     }
13 }
 1 /**
 2  * C系统敏感词过滤
 3  *
 4  * @author zhoude
 5  * @date 2020/4/11 13:00
 6  */
 7 public class CThirdFilter {
 8 
 9     public String filter(String text, String mask) {
10         // 伪实现
11         return mask;
12     }
13 }
 1 public class Test {
 2 
 3     private AThirdFilter aThirdFilter = new AThirdFilter();
 4     private BThirdFilter bThirdFilter = new BThirdFilter();
 5     private CThirdFilter cThirdFilter = new CThirdFilter();
 6 
 7     public String filter(String text) {
 8         // 未使用适配器模式之前的代码:代码的可测试性、扩展性不好
 9         String result = aThirdFilter.filterPoliticalWords(text);
10         result = aThirdFilter.filterSexyWords(result);
11         result = bThirdFilter.filter(result);
12         result = cThirdFilter.filter(result, "***");
13         return result;
14     }
15 }

使用之后:

1 public interface IThirdFilter {
2 
3     String filter(String text);
4 }
 1 public class AThirdFilterImpl implements IThirdFilter {
 2 
 3     private AThirdFilter filter;
 4 
 5     public AThirdFilterImpl(AThirdFilter aThirdFilter) {
 6         this.filter = aThirdFilter;
 7     }
 8 
 9     @Override
10     public String filter(String text) {
11         String result = filter.filterPoliticalWords(text);
12         result = filter.filterSexyWords(result);
13         return result;
14     }
15 }
 1 public class BThirdFilterImpl implements IThirdFilter {
 2 
 3     private BThirdFilter filter;
 4 
 5     public BThirdFilterImpl(BThirdFilter aThirdFilter) {
 6         this.filter = aThirdFilter;
 7     }
 8 
 9     @Override
10     public String filter(String text) {
11         return filter.filter(text);
12     }
13 }
 1 public class CThirdFilterImpl implements IThirdFilter {
 2 
 3     private CThirdFilter filter;
 4 
 5     public CThirdFilterImpl(CThirdFilter aThirdFilter) {
 6         this.filter = aThirdFilter;
 7     }
 8 
 9     @Override
10     public String filter(String text) {
11         return filter.filter(text, "***");
12     }
13 }
 1 public class Test {
 2 
 3     private List<IThirdFilter> filterList = new ArrayList<>();
 4 
 5     public void addFilter(IThirdFilter filter) {
 6         filterList.add(filter);
 7     }
 8 
 9     public String filter(String text) {
10         String result = text;
11         for (IThirdFilter filter : filterList) {
12             result = filter.filter(result);
13         }
14         return result;
15     }
16 }

———————————————————————————————————————————————————————

3、替换依赖的外部系统:当我们把项目中依赖的一个外部系统替换为另一个外部系统的时候,利用适配器模式,可以减少对代码的改动。

———————————————————————————————————————————————————————

4、适配不同的数据格式:如Java 中的 Arrays.asList()。

代理、桥接、装饰、适配器区别

  • 代理模式:代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。
  • 桥接模式:桥接模式的目的是将接口部分和实现部分分离,从而让它们可以较为容易、也相对独立地加以改变。
  • 装饰器模式:装饰者模式在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器的嵌套使用。
  • 适配器模式:适配器模式是一种事后的补救策略。适配器提供跟原始类不同的接口,而代理模式、装饰器模式提供的都是跟原始类相同的接口。
posted @ 2020-04-11 13:17  被猪附身的人  阅读(199)  评论(0编辑  收藏  举报