源码地址 | https://github.com/DingMouRen/DesignPattern |
---|
1.定义
将不兼容的接口转换成可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。例子:USB转接头充当适配器,把两种不兼容的接口,通过转变变得可以一起工作。
2.适配器的两种实现方式
- 类适配器:通过继承关系来实现
- 对象适配器:通过组合关系来实现
3.类适配器
ITarget 表示要转化成的接口定义。Adaptee 是一组不兼容 ITarget 接口定义的接口,Adaptor 将 Adaptee 转化成一组符合 ITarget 接口定义的接口
/**
* 要转化成的接口定义
*/
public interface ITarget {
void f1();
void f2();
void fc();
}
/**
* 被适配者
*/
public class Adaptee {
public void fa(){
}
public void fb(){
}
public void fc(){
}
}
/**
* 适配器,
*/
public class Adaptor extends Adaptee implements ITarget{
@Override
public void f1() {
super.fa();
}
@Override
public void f2() {
//重现实现f2()
}
//这里fc()不需要实现,直接继承自Adaptee,这是跟对象适配器最大的不同
}
4.对象适配器
/**
* 对象适配器
*/
public interface ITarget {
void f1();
void f2();
void fc();
}
/**
* 被适配者
*/
public class Adaptee {
public void fa(){
}
public void fb(){
}
public void fc(){
}
}
/**
* 适配器
*/
public class Adaptor implements ITarget {
private Adaptee adaptee;
public Adaptor(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void f1() {
adaptee.fa();//委托给adaptee来实现
}
@Override
public void f2() {
//重新实现f2()
}
@Override
public void fc() {
adaptee.fc();
}
}
5.类适配器与对象适配器如何选择?
- 如果Adaptee接口不多,两种方式都可以
- 如果Adaptee接口很多,而且Adaptee和ITarget接口定义大部分都相同,推荐使用类适配器,因为Adaptor复用父类Adaptee的接口,比起对象适配器的实现方式,Adaptor的代码量少一些
- 如果Adaptee接口很多,而且Adaptee和ITarget接口定义大部分都不相同,推荐使用对象适配器,因为组合结构相对继承更加灵活
6.应用场景
- 封装有缺陷的接口设计。
假设我们依赖的外部系统在接口设计方面有缺陷,比如包含大量静态方法,引入之后会影响到我们自身代码的可测试性。为了隔离设计上的缺陷,我们希望对外部系统提供的接口进行二次封装,抽象出更好的接口设计。这时候可以使用适配器模式。
/**
* 这个类来自外部sdk,我们无权修改它的代码
*/
public class CD {
public static void staticFunction1(){
System.out.println("staticFunction1");
}
public void uglyNamingFunction2(){
}
public void tooManyParamsFunction3(int paramA,int paramB){
}
public void lowPerformanceFunction4(){
}
}
/**
* 使用适配器模式进行重构
*/
public interface ITarget {
void function1();
void function2();
void function3(ParamsWrapperDefinition paramsWrapper);
void function4();
}
/**
* 参数封装
*/
public class ParamsWrapperDefinition {
public int getParamA(){
return 1;
}
public int getParamB(){
return 1;
}
}
/**
* 适配器
*/
public class CDAdaptor extends CD implements ITarget {
@Override
public void function1() {
staticFunction1();
}
@Override
public void function2() {
super.uglyNamingFunction2();
}
@Override
public void function3(ParamsWrapperDefinition paramsWrapper) {
super.tooManyParamsFunction3(paramsWrapper.getParamA(), paramsWrapper.getParamB());
}
@Override
public void function4() {
//重新实现function4()
}
}
/**
* 使用类
*/
public class Client {
public static void main(String[] args) {
CDAdaptor adaptor = new CDAdaptor();
adaptor.function1();
}
}
- 替换依赖的外部系统
当我们把项目中依赖的一个外部系统替换成另一个外部系统的时候,使用适配器模式,可以减少对代码的改动.
/**
* 外部系统A
*/
public interface IA {
void fa();
}
public class A implements IA{
@Override
public void fa() {
System.out.println("A方法执行");
}
}
/**
* 外部系统B
*/
public interface IB {
void fb();
}
/**
* 外部系统B
*/
public class B implements IB{
@Override
public void fb() {
System.out.println("B方法执行");
}
}
/**
* 系统调用者
*/
public class AManager {
private IA a;
public AManager(IA a) {
this.a = a;
}
public void function(){
a.fa();
}
}
/**
* 将外部系统A替换成系统B的适配器
*/
public class BAdaptor implements IA {
private B b;
public BAdaptor(B b) {
this.b = b;
}
@Override
public void fa() {
b.fb();
}
}
/**
* 使用者
*/
public class Client {
public static void main(String[] args) {
AManager aManager = new AManager(new A());
aManager.function();
AManager aManager1 = new AManager(new BAdaptor(new B()));
aManager1.function();
}
}
- 统一多个类的接口设计.
某个功能的实现依赖多个类,可以通过适配器模式,将它们的接口适配成统一的接口定义,然后使用多态的特性来复用代码逻辑。
场景:
假设我们的系统要对用户输入的文本内容做敏感词过滤,为了提高过滤的召回率,我们引入了多款第三方敏感词过滤系统,依次对用户输入的内容进行过滤,过滤掉尽可能多的敏感词。但是,每个系统提供的过滤接口都是不同的。这就意味着我们没法复用一套逻辑来调用各个系统。这个时候,我们就可以使用适配器模式,将所有系统的接口适配为统一的接口定义,这样我们可以复用调用敏感词过滤的代码.
/**
* A敏感词过滤系统提供的接口
*/
public class ASensitiveWordsFilter {
/**
*
* @param text 原始文本
* @return 去除敏感词后的文本
*/
public String filterSexyWords(String text){
/*
敏感词处理逻辑
*/
System.out.println("敏感词A-sexy处理");
return "";
}
public String filterPoliticalWords(String text){
/*
敏感词处理逻辑
*/
System.out.println("敏感词A-political处理");
return "";
}
}
/**
* B敏感词过滤系统
*/
public class BSensitiveWordsFilter {
public String filter(String text){
/*
敏感词处理逻辑
*/
System.out.println("敏感词B处理");
return "";
}
}
/**
* C敏感词过滤系统
*/
public class CSensitiveWordsFilter {
public String filter(String text,String mask){
/*
敏感词处理逻辑
*/
System.out.println("敏感词C处理");
return "";
}
}
/**
* 使用配置器模式进行改造,统一接口定义
*/
public interface ISensitiveWordsFilter {
String filter(String text);
}
/**
* 敏感词A系统的适配器
*/
public class ASensitiveWordsFilterAdaptor implements ISensitiveWordsFilter {
private ASensitiveWordsFilter aFilter;
public ASensitiveWordsFilterAdaptor(ASensitiveWordsFilter aFilter) {
this.aFilter = aFilter;
}
@Override
public String filter(String text) {
String maskedText = aFilter.filterSexyWords(text);
maskedText = aFilter.filterPoliticalWords(maskedText);
return maskedText;
}
}
/**
* 敏感词B系统的适配器
*/
public class BSensitiveWordsFilterAdaptor implements ISensitiveWordsFilter {
private BSensitiveWordsFilter bFilter;
public BSensitiveWordsFilterAdaptor(BSensitiveWordsFilter bFilter) {
this.bFilter = bFilter;
}
@Override
public String filter(String text) {
String maskedText = bFilter.filter(text);
return maskedText;
}
}
/**
* 敏感词C系统的适配器
*/
public class CSensitiveWordsFilterAdaptor implements ISensitiveWordsFilter {
private CSensitiveWordsFilter cFilter;
public CSensitiveWordsFilterAdaptor(CSensitiveWordsFilter cFilter) {
this.cFilter = cFilter;
}
@Override
public String filter(String text) {
String maskedText = cFilter.filter(text,"");
return maskedText;
}
}
/**
* 扩展性好,符合开闭原则,如果添加一个新的敏感词过滤系统,这个类也不用
* 改动,基于接口而非实现编程,代码的可测试性好
*/
public class RiskManagement {
private List<ISensitiveWordsFilter> filters = new ArrayList<>();
public void addSensitiveWordsFilter(ISensitiveWordsFilter filter){
filters.add(filter);
}
public String filterSensitiveWords(String text){
String maskedText = text;
for (ISensitiveWordsFilter filter: filters) {
maskedText = filter.filter(maskedText);
}
return maskedText;
}
}
/**
* 使用者
*/
public class Client {
public static void main(String[] args) {
RiskManagement riskManagement = new RiskManagement();
riskManagement.addSensitiveWordsFilter(new ASensitiveWordsFilterAdaptor(new ASensitiveWordsFilter()));
riskManagement.addSensitiveWordsFilter(new BSensitiveWordsFilterAdaptor(new BSensitiveWordsFilter()));
riskManagement.addSensitiveWordsFilter(new CSensitiveWordsFilterAdaptor(new CSensitiveWordsFilter()));
riskManagement.filterSensitiveWords("text");
}
}
7.代理、桥接、装饰器、适配器4种设计模式的区别
这4种模式是比较常用的结构型设计模式,代码结构相似,通过wrapper类二次封装原始类,可以称为wrapper模式
代理模式:在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是与装饰器模式最大的不通
桥接模式:将接口部分和实现部分分离,从而让它们较为容易、也相对独立的加以变化
装饰器模式:在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器嵌套使用。
适配器模式:在某个方面上来讲,是一种事后的补救策略。适配器提供与原始类不同的接口,而代理模式、装饰器模式提供的都是跟原始类相同的接口。
网友评论