Java Code DesignPartten

设计模式-适配器模式

Posted on 2020-09-24,7 min read

定义

  • Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.(将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。)
  • 适配器模式就是把一个接口或类转换成其他的接口或类
  • 分类:由于Java只支持单继承,所以适配器模式也分为类适配器和对象适配器。
  • 类适配器:使用类间继承,只能通过复写原角色的方法进行扩展。
  • 对象适配器:使用类间关联进行耦合,设计时候比较灵活
  • 组成:
    • Target目标角色:该角色定义把其他类转换为何种接口,也就是我们的期望接口
    • Adaptee原角色:想把谁转换成目标角色,这个"谁"就是源角色,它是已经存在的、运行良好的类或对象,结果适配器角色的包装,它会成为 一个新的角色
    • Adapter适配器角色:把原角色转换为目标角色,通过继承或是类的关联
  • 通用类图

类适配器类图

适配器模式通用类图

对象适配器通用类图

对象适配器通用类图

优点

  • 适配器模式可以让两个没有任何关系的类在一起运行。
  • 增加了类的透明性:我们访问的Target目标角色,但是具体的实现都委托给了源角色,而这些对高层次模块是透明的,也是它不需要关心的
  • 提高了类的复用度:源角色在原有的系统中还是可以正常使用,而在目标角色中也可以充当新的演员
  • 灵活性非常好:如果突然不想要适配器,没问题,删除掉这个适配器就可以了,其他的代码都不用修改,基本上就类似一个灵活的构件,想用就用,不想就卸载

使用场景

  • 场景:
    • 有动机修改一个已经投产中的接口:比如系统扩展,需要要使用一个已有或新建立的类,但这个类又不符合系统的接口,就可以使用适配器模式

代码

适配器模式是在后期维护的时候考虑的设计模式,而不是在设计的时候考虑的设计模式。同时根据应用场景,适配器模式需要进行灵活的扩展,下面是适配器模式的一个基本框架

由于Java不支持多继承。如果一个原角色的用户类的各个信息是分开的(如:用户基本信息一个接口一个类,用户家庭信息一个接口一个类。符合单一职责原则),那么类适配器就不适用了,此时应该使用对象适配器来解决。

类适配器

类适配器本实例类图

代码

被转换角色(普通类

package com.pattern.adapter.classadapter.adaptee;

/**
 * 类适配器
 * 原角色,需要被转换的角色
 */
public class ClassAdaptee {
    public void AdapteeMethod(){
        System.out.println("原角色的方法");
    }
}

目标角色接口(接口

package com.pattern.adapter.classadapter.target;

/**
 * 类适配器
 * 目标角色接口,需要被转换成的角色接口
 */
public interface ClassAdapterTarget {
    // 目标角色自己的方法
    void TargetMethod();
}

具体目标角色(实现目标角色接口

package com.pattern.adapter.classadapter.target;
/**
 * 类适配器
 * 目标角色,需要被转换成的角色
 */
public class ConcreteClassAdapterTarget implements ClassAdapterTarget {
    @Override
    public void TargetMethod() {
        System.out.println("具体的目标角色的方法");
    }
}

适配器(普通类

package com.pattern.adapter.classadapter;

import com.pattern.adapter.classadapter.adaptee.ClassAdaptee;
import com.pattern.adapter.classadapter.target.ClassAdapterTarget;

/**
 * 类适配器
 * 适配器角色,用于转换
 */
public class ClassAdapter extends ClassAdaptee implements ClassAdapterTarget {
    @Override
    public void TargetMethod() {
        super.AdapteeMethod();
    }
}

测试代码

package com.pattern;

import com.pattern.adapter.classadapter.ClassAdapter;
import com.pattern.adapter.classadapter.adaptee.ClassAdaptee;
import com.pattern.adapter.classadapter.target.ConcreteClassAdapterTarget;
import com.pattern.adapter.classadapter.target.ClassAdapterTarget;
import com.pattern.adapter.objectadapter.ObjectAdapter;
import com.pattern.adapter.objectadapter.adaptee.IObjectAdapteeInf;
import com.pattern.adapter.objectadapter.adaptee.IObjectAdapteeName;
import com.pattern.adapter.objectadapter.adaptee.impl.ObjectAdapteeInf;
import com.pattern.adapter.objectadapter.adaptee.impl.ObjectAdapteeName;
import com.pattern.adapter.objectadapter.target.ObjectAdapterTarget;
import org.junit.Test;

public class AdapterTest {
    /**
     * 类适配器测试
     */
    @Test
    public void classAdapterTest(){
        System.out.println("-------定义一个原角色-------");
        ClassAdaptee adaptee = new ClassAdaptee();
        adaptee.AdapteeMethod();
        System.out.println("-------定义一个目标角色-------");
        ClassAdapterTarget target = new ConcreteClassAdapterTarget();
        target.TargetMethod();
        System.out.println("-------定义由原角色转换来的目标角色-------");
        ClassAdapter adapter = new ClassAdapter();
        adapter.AdapteeMethod();
    }

}

结果

适配器模式运行结果

对象适配器

对象适配器本实例类图

代码

被转换角色名字接口(接口

package com.pattern.adapter.objectadapter.adaptee;

public interface IObjectAdapteeName {
     String getName();
}

被转换角色名字实现(实现被转换角色名字接口

package com.pattern.adapter.objectadapter.adaptee.impl;

import com.pattern.adapter.objectadapter.adaptee.IObjectAdapteeName;

public class ObjectAdapteeName implements IObjectAdapteeName {
    @Override
    public String getName() {
        return "Name";
    }
}

被转换角色信息接口(接口

package com.pattern.adapter.objectadapter.adaptee;

public interface IObjectAdapteeInf {
    String getInformation();
}

被转换角色信息实现(实现被转换角色名字接口

package com.pattern.adapter.objectadapter.adaptee.impl;

import com.pattern.adapter.objectadapter.adaptee.IObjectAdapteeInf;

public class ObjectAdapteeInf implements IObjectAdapteeInf {
    @Override
    public String getInformation() {
        return "Information";
    }
}

目标角色接口(接口

package com.pattern.adapter.objectadapter.target;

public interface ObjectAdapterTarget {
    String getName();
    String getInformation();
}

适配器(实现目标角色接口

package com.pattern.adapter.objectadapter;

import com.pattern.adapter.objectadapter.adaptee.IObjectAdapteeInf;
import com.pattern.adapter.objectadapter.adaptee.IObjectAdapteeName;
import com.pattern.adapter.objectadapter.target.ObjectAdapterTarget;

public class ObjectAdapter implements ObjectAdapterTarget {
    private IObjectAdapteeName objectAdapteeName;
    private IObjectAdapteeInf objectAdapteeInf;

    public ObjectAdapter(IObjectAdapteeName objectAdapteeName, IObjectAdapteeInf objectAdapteeInf) {
        this.objectAdapteeName = objectAdapteeName;
        this.objectAdapteeInf = objectAdapteeInf;
    }

    @Override
    public String getName() {
        return this.objectAdapteeName.getName();
    }

    @Override
    public String getInformation() {
        return this.objectAdapteeInf.getInformation();
    }
}

测试代码

package com.pattern;

import com.pattern.adapter.classadapter.ClassAdapter;
import com.pattern.adapter.classadapter.adaptee.ClassAdaptee;
import com.pattern.adapter.classadapter.target.ConcreteClassAdapterTarget;
import com.pattern.adapter.classadapter.target.ClassAdapterTarget;
import com.pattern.adapter.objectadapter.ObjectAdapter;
import com.pattern.adapter.objectadapter.adaptee.IObjectAdapteeInf;
import com.pattern.adapter.objectadapter.adaptee.IObjectAdapteeName;
import com.pattern.adapter.objectadapter.adaptee.impl.ObjectAdapteeInf;
import com.pattern.adapter.objectadapter.adaptee.impl.ObjectAdapteeName;
import com.pattern.adapter.objectadapter.target.ObjectAdapterTarget;
import org.junit.Test;

public class AdapterTest {
    /**
     * 对象适配器测试
     */
    @Test
    public void objectAdapterTest(){
        System.out.println("-------定义一个原角色的信息-------");
        IObjectAdapteeName objectAdapteeName = new ObjectAdapteeName();
        IObjectAdapteeInf objectAdapteeInf = new ObjectAdapteeInf();
        System.out.println("-------定义一个目标角色-------");
        ObjectAdapterTarget target = new ObjectAdapter(objectAdapteeName,objectAdapteeInf);
        System.out.println("-------打印目标角色信息-------");
        System.out.println(target.getName());
        System.out.println(target.getInformation());

    }
}

结果

对象适配器运行结果

注意

  • 在装饰者模式中,必然有一个最基本、最核心、最原始的接口或抽象充当Component抽象构件
  • 原始方法和装饰方法的执行顺序在具体的装饰类是固定的,可以通过方法重载实现多种执行顺序
  • 适配器模式是一种补救模式,通常用来解决接口不相容的问题。在设计中是不可能用到的
  • 对象适配器较类适配器更为灵活,项目中更常使用对象适配器

下一篇: 设计模式-责任链模式→

loading...