您的位置:首页 > 其它

设计模式-结构型之适配器模式

2015-08-27 22:13 120 查看

模式动机

  适配是指“源”到“目标”能够匹配、兼容,两者之间的中间件就叫适配器。适配器主要是起到“源”到“目标”的一个过渡作用,负责把“源”转换成我们想要的“目标”。

  比如,假设我们系统中现在存在了一个Bird(鸟)类,Bird里面有自己的一个fly()方法,还存在一个Tiger(老虎)类,Tiger里面有自己的一个run()方法。同时,我们定义了一个Moveable接口(把“可移动”这种行为抽象出来的一个标准接口),里面有一个抽象方法move(),客户端程序是调用的标准接口Moveable,现在客户端希望通过这个标准接口让鸟儿和老虎移动起来,很显然,鸟儿移动是靠飞翔,老虎移动是靠奔跑,此时我们我们应该怎么办,如何能将两者适配起来?当然,可能都会首先想到修改Bird跟Tiger的代码,让其实现Moveable接口不就行了么。但假如Bir跟Tiger是引入的外部的程序,我们没有源码呢?同时,即使可以修改源码,这么做也有悖于高内聚低耦合的原则。此时,我们便需要使用适配器模式来解决!

模式定义

  将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)

类适配器

  适配器模式有两种实现,一种是类适配器,另一种是对象适配器。首先介绍类适配器,类适配器的结构如下:

  


  Target为我们的目标接口,Adaptee是我们的”源“,也就是适配者,Adapter则为两者之间的适配器。直接看代码:

//这个是"源",相当于类图中的Adaptee,我们希望能够转换成我们的目标接口Moveable
public class Bird {
public void fly(){
System.out.println("我是鸟,我飞翔");
}
}


//这个是目标,相当于类图中的Target,是用户所期望的标准接口
public interface Moveable {
public abstract void move();
}


//这个便是适配器,相当于类图中的Adapter
public class BirdAdapter extends Bird implements Moveable{
@Override
public void move() {
this.fly();
}
}


//客户端程序,控制台打印出:我是鸟,我飞翔
public class Client {
public static void main(String[] args) {
Moveable m1 = new BirdAdapter();
m1.move();
}
}


  可以看到,我们的适配器BirdAdapter继承了Bird类,然后实现了Moveable接口,然后在重写move方法时调用”源“的具体方法,达到了适配的效果。但问题来了,我们还需要适配Tiger类,甚至还有更多。显然,由于java是单继承,而我们的代码中BirdAdapter已经继承了Bird类,所以我们只能再另外写一个适配器TigerAdapter。也就是说我们的这个适配器只能为Bird一个类服务,所以这种适配器就叫类适配器。

对象适配器

  接下来看看什么是对象适配器,直接看代码:

  Bird类跟Moveable接口代码都不变,只是适配器类的代码需要改变,如下:

public class Adapter implements Moveable{
private Bird bird;
public Adapter(Bird bird){
this.bird = bird;
}
@Override
public void move() {
bird.fly();
}
}


  可以看到,此时的适配器类不再继承Bird类,而是把bird作为一个成员变量,然后调用bird.fly(),这样就不再受java单继承的限制,可以对多个”源“进行适配。举个例子,假设现在还有一个Tiger类,老虎类代码如下:

public class Tiger {
public void run(){
System.out.println("我是老虎,我奔跑");
}
}


  现在还需要对Tiger进行适配,那么我们的适配器Adapter就可以这样写:

public class Adapter implements Moveable{
private Object obj;
public Adapter(Object obj){
this.obj = obj;
}
@Override
public void move() {
if(obj instanceof Bird){
((Bird) obj).fly();
}else if(obj instanceof Tiger){
((Tiger) obj).run();
}
}
}


  客户端根据需要传入相应的”源“对象即可。

public class Client {
public static void main(String[] args) {
Moveable m = new Adapter(new Tiger());
m.move();
}
}


  这便是对象适配器,它把“源”作为一个构造参数传入适配器,然后执行接口所要求的方法。这种适配模式可以为多个源进行适配。弥补了类适配模式的不足。

模式延伸-默认适配器

  当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。因此也称为单接口适配器模式。简单举例如下:

public interface Target {
public abstract void m1();
public abstract void m2();
public abstract void m3();
}


//默认适配器
public class DefaultAdapter implements Target{
@Override
public void m1() {

}
@Override
public void m2() {

}
@Override
public void m3() {

}
}


public class Concrete  extends DefaultAdapter{
@Override
public void m3(){
System.out.println("我只想重写m3方法,其他的我不想管");
}
}


适用场景

系统需要使用现有的类,而这些类的接口不符合系统的需要

想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: