从这篇博文开始,我们将讲下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源。
接下来,我们学习结构性、型模式的第一种模式:适配器模式。
一、适配器模式
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分三类:类的适配器模式、对象的适配器模式、接口的适配器模式。其实我觉得接口的适配器不是很符合适配器模式,但是也是很有用的,这里就加进来说明了。
二、类的适配器
核心思想是:有一个Source类,拥有一个方法,待适配,目标接口是Targetable,通过Adapter类,将Source的功能扩展到Targetable里。
1、UML
2、Source
/**
* 原来的类
* @author suibibk.com
*
*/
public class Source {
public void method1() {
System.out.println("我是方法1");
}
}
3、Targetable
/**
* 目标接口
* @author suibibk.com
*
*/
public interface Targetable {
public void method1();
public void method2();
}
4、Adapter
/**
* 这样子,这个类不仅仅有Source方法1的能力,还有方法2的能力
* @author suibibk.com
*
*/
public class Adapter extends Source implements Targetable {
@Override
public void method2() {
System.out.println("我是方法2");
}
}
5、测试类Test
public class Test {
public static void main(String[] args) {
Adapter adapter = new Adapter();
adapter.method1();
adapter.method2();
}
}
运行测试类,输出如下结果
我是方法1
我是方法2
这也就表明,我们扩展了原先的Source类,本来只有方法1 的功能的,现在也拥有了方法2的功能,并不影响使用。
二、对象适配器
基本思路和类的适配器模式相同,只是将Adapter类做修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。
1、UML
2、Source
/**
* 原来的类
* @author suibibk.com
*
*/
public class Source {
public void method1() {
System.out.println("我是方法1");
}
}
3、Targetable
/**
* 目标接口
* @author suibibk.com
*
*/
public interface Targetable {
public void method1();
public void method2();
}
4、Adapter类
/**
* 这样子,这个类不仅仅有Source方法1的能力,还有方法2的能力
* @author suibibk.com
*
*/
public class Adapter implements Targetable {
private Source source;
public Adapter(Source source){
this.source =source;
}
@Override
public void method2() {
System.out.println("我是方法2");
}
@Override
public void method1() {
source.method1();
}
}
注意,这里没有用继承,用的是依赖。
5、测试类Test
public class Test {
public static void main(String[] args) {
Adapter adapter = new Adapter(new Source());
adapter.method1();
adapter.method2();
}
}
输出结果当然跟上面是一样的
三、接口的适配器
第三种适配器模式是接口的适配器模式,接口的适配器模式是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这个明显是比较浪费的,因为并不是所有方法都是我们需要的,有时只需要某一些,此处为解决这个问题,我们引入礼物接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,之和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。
1、UML
2、Sourceable
/**
* 目标接口
* @author suibibk.com
*
*/
public interface Sourceable {
public void method1();
public void method2();
}
目标接口可能会有超级多的方法。
3、抽象类Wrapper
public abstract class Wrapper implements Sourceable{
@Override
public void method1() {};
@Override
public void method2() {};
}
对目标接口的所有方法进行假实现。
4、SourceSub1、SourceSub2
/**
* 实现方法1
* @author suibibk.com
*
*/
public class SourceSub1 extends Wrapper{
public void method1() {
System.out.println("我是方法1");
}
}
/**
* 实现方法2
* @author suibibk.com
*
*/
public class SourceSub2 extends Wrapper{
public void method2() {
System.out.println("我是方法2");
}
}
这样子就不需要实现所有方法了。
5、测试类Test
public class Test {
public static void main(String[] args) {
SourceSub1 sourceSub1 = new SourceSub1();
SourceSub2 sourceSub2 = new SourceSub2();
sourceSub1.method1();
sourceSub2.method2();
}
}
运行测试,结果当然是一样的。
总结
讲了这么多,总结一下三种适配器模式的应用场景:
类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Adapter类的方法中,调用实例的方法就行。
接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有的方法,我们写别的类的时候,继承抽象类即可。(我觉得这个可以不需要接口,也不太算属于适配器的模式)