适配器模式
适配器从使用目的上来说,也可以分为两种,定制适配器和缺省适配器,这两种的区别在于使用目的上的不同,一种为了复用原有的代码并适配当前的接口,一种为了提供缺省的实现,避免子类需要实现不该实现的方法。定制适配器从实现方式上又分为两种,类适配器和对象适配器,这两种的区别在于实现方式上的不同,一种采用继承,一种采用组合的方式。
如何使用
1、类适配器
当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。举个例子,首先有一个监听接口,有一个教师类,里面有一个方法用来通知学生下课,方法的参数是一个实现了监听接口的实体,还有一个助教类,助教类中有一个方法是辅导作业,再不改变原有类的基础上,我们想让助教在教师宣布放学的时候也能收到通知,而后辅导学生写作业,这个时候我们就可以编写一个类适配器,让其继承助教类同时实现监听接口,这样就能在不修改代码的基础上,将助教类适配成一个实现了监听接口的类,同时保留了原有功能。
类图如下:
简单demo:
package adapter; public interface IListener { void classOver(); }
package adapter; public class Student implements IListener { @Override public void classOver() { System.out.println("放学啦"); writeHomework(); } private void writeHomework() { System.out.println("学生写作业"); } }
package adapter; public class Assistant { public void helpStudent() { System.out.println("辅导学生写作业"); } }
package adapter; public class Teather { public void notifyClassOver(IListener listener) { listener.classOver(); } }
package adapter; public class AssistantAdapter extends Assistant implements IListener{ @Override public void classOver() { System.out.println("放学啦"); super.helpStudent(); } }
2、对象适配器
当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个adapter类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。在上面的场景中我们还可以做一个对象适配器,让其持有一个助教类的对象并且实现监听接口,在实现的方法调用助教对象的方法。
类图如下:
简单demo,修改适配器如下:
package adapter; public class AssistantAdapter2 implements IListener{ private Assistant assistant; public AssistantAdapter2(Assistant assistant) { super(); this.assistant = assistant; } public Assistant getAssistant() { return assistant; } public void setAssistant(Assistant assistant) { this.assistant = assistant; } @Override public void classOver() { System.out.println("放学啦"); assistant.helpStudent(); } }
3、接口适配器
接口适配器非常简单,几个例子就是我们的监听接口里有很多方法,比如下课、上课、开会、吃饭等等,但我们的学生类只关心上下课,这个时候我们可以做一个接口适配器,它是一个抽象类,对接口的方法做了空实现,具体的学生类再继承接口适配器,对自己感兴趣的方法进行复写即可。java8之后(包含java8)允许接口有默认实现,所以后面我们会看到使用接口适配器会越来越少。
使用场景
类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景:
(1)想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
(2)我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。
以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。
接口适配器使用场景:
想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。