设计模式篇->03适配器模式

设计模式篇->03适配器模式_第1张图片
适配器模式通用UML类图

一、适配器模式定义

    将一个类的接口变换成客户端所期待的另一种接口, 从而使原本因接口不匹配而无法在一起工作的两
个类能够在一起工作;

二、适配器模式的三个角色

1. Target目标角色;
2. Adaptee源角色;
3. Adapter适配器角色;
2.1 Target目标角色
该角色定义把其他类转换为何种接口, 也就是我们的期望接口;
2.2 Adaptee源角色
你想要把谁转换成目标角色, 这个"谁"就是源角色, 它是已经存在的、运行良好的类或对象, 经过适配
器角色的包装, 它会成为目标角色;
2.3 Adapter适配器角色
适配器模式的核心角色, 其他两个角色都是已经存在的角色, 而适配器角色是需要新建立的, 它的职责
非常简单: 把源角色转换为目标角色, 怎么转换? 通过继承或是类关联的方式;

三、通用代码

3.1 类适配器通用代码
// 目标角色
public interface Target {
    //目标角色有自己的方法
    public void  request();
}

目标角色是一个已经在正式运行的角色, 你不可能去修改角色中的方法, 你能做的就是如何去实现接口
中的方法, 而且通常情况下, 目标角色是一个接口或者是一个抽象类, 一般不会是实现类.
// 目标角色的实现类
public class ConcreteTarget implements Target {
    @Override
    public void request() {
        System.out.println("ConcreteTarget->request()");
    }
}

// 源角色: 源角色是一个已经存在的类, 它是一个正常的类, 此时我们不可能改变这个类;
public class Adaptee {
    public void doSomething() {
        System.out.println("Adaptee->doSomething()");
    }
}

// 注意在类适配器的情况下, 适配器是如何做的;
// 此时采取的是继承的方式;
public class Adapter extends Adaptee implements Target {
    @Override
    public void request() {
        super.doSomething();
    }
}

public class Client {
    public static void main(String[] args) {
        //原有的业务逻辑
        Target target1 = new ConcreteTarget();
        target1.request();
        //现在增加了适配器角色后的业务逻辑
        Target target2 = new Adapter();
        target2.request();
    }
}
3.2 对象适配器通用代码(使用FutureTask兼容Runnable的伪代码)
下面代码是对FutureTask支持Callable和Runnable的伪代码, 下文对FutureTask进行了详细的描述;
public class A {
    private B b;
    public A(B b) {
        this.b = b;
    }
    public void methodA() {
        this.b.methodB();
    }
}

public class B {
    public void methodB() {...}
}

public class C {
    public void methodC() {...}
}
接下来我们希望A能够支持C但是对外暴露的接口不变, 该怎么办?
public class A {
    private B b;
    public A(B b) {
        this.b = b;
    }
    public A(C c) {
        CAdapter cadapter = new CAdapter(c);
        b = cadapter;
    }
    public void methodA() {
        this.b.methodB();
    }
}

public class CAdapter extends B {
    private C c;
    @Override
    public void methodB() {
        c.methodC();
    }
}

四、适用场景 :

  适配器应用的场景只要记住一点就足够了: 你有动机修改一个已经投产中的接口时, 适配器模式可能是最适合你的模式. 比如系统扩展了, 需要使用一个已有或新建立的类, 但这个类又不符合系统的接口, 怎么办? 使用适配器模式;

五、适配器模式的好处 :

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

6. 适配器模式在源码中的运用 :

  AsyncTask内部使用了FutureTask, 大致流程如下:

public class AsyncTask {
    public final AsyncTask<...> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    public final AsyncTask<...> executeOnExecutor(Executor exec, Params... params) {
        mWorker.mParams = params;
        exec.execute(mFuture);
        return this;
    }
    public AsyncTask() {
        mWorker = new WorkerRunnable() {
            public Result call() throws Exception {...}
        };
        mFuture = new FutureTask(mWorker) {
            @Override
            protected void done() {...}
        };
    }
}

  当Executor执行execute方法时, 会触使mFuture调用其内部的run方法;

public class FutureTask implements RunnableFuture {...}
public interface RunnableFuture extends Runnable, Future {...}
private static abstract class WorkerRunnable implements Callable {...}

  表面要调用FutureTask的run(), 但是实际却执行到了WorkerRunnable的call(), FutureTask如何实现Callable与Runnable的关联?

public class FutureTask implements RunnableFuture {
    public FutureTask(Callable callable) {
        this.callable = callable;
    }
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
    }
}

  FutureTask构造函数接收两种参数类型: Callable与Runnable类型, 当传入的参数为Runnable类型时;

public class Executors {
    public static  Callable callable(Runnable task, T result) {
        return new RunnableAdapter(task, result);
    }
}
private static final class RunnableAdapter implements Callable {
    private final Runnable task;
    RunnableAdapter(Runnable task) {
        this.task = task;
    }
    public T call() {
        task.run();
        return result;
    }
}

  Runnable会被转为RunnableAdapter对象, RunnableAdapter对象持有Runnable的引用, 而RunnableAdapter又实现于Callable;
  当Executor.execute(FutureTask)时, 会触发FutureTask的run()的执行 :

public class FutureTask implements RunnableFuture {
    public void run() {
        Callable c = callable;
        if (c != null && state == NEW) {
            result = c.call();
        }
    }
}

  实际上指向了Callable的call()方法, 而此时Callable实际指向RunnableAdapter, 最终执行了Runnable的run方法;

你可能感兴趣的:(设计模式篇->03适配器模式)