美文网首页
适配器模式(封装对象,并提供不同的接口)

适配器模式(封装对象,并提供不同的接口)

作者: 钉某人 | 来源:发表于2017-11-17 10:30 被阅读0次
    源码地址 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模式

    代理模式:在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是与装饰器模式最大的不通

    桥接模式:将接口部分和实现部分分离,从而让它们较为容易、也相对独立的加以变化

    装饰器模式:在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器嵌套使用。

    适配器模式:在某个方面上来讲,是一种事后的补救策略。适配器提供与原始类不同的接口,而代理模式、装饰器模式提供的都是跟原始类相同的接口。

    相关文章

      网友评论

          本文标题:适配器模式(封装对象,并提供不同的接口)

          本文链接:https://www.haomeiwen.com/subject/vvidvxtx.html