概述
适配器模式(Adapter Pattern):消除类、对象、接口不匹配而造成的的兼容性问题,起桥梁作用
根据使用可以归结为三类
适配模式 | 描述 |
---|---|
类适配 | 将一个类转换成满足另一个新接口的类——创建一个新类,继承原有的类,实现新的接口 |
对象适配 | 将一个对象转换成满足另一个新接口的对象——持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行 |
接口适配 | 不希望实现一个接口中所有的方法——抽象类实现所有方法,新创建类时,继承抽象类 |
涉及角色
- target
对象:该角色负责定义所需的方法 - client
请求者:该角色负责使用target角色所定义的方法进行具体处理 - adaptee
被适配:持有特定方法的角色 - adapter
适配:使用adaptee角色的方法来满足target角色的需求,这是adapter模式的目的,也是adapter角色的作用。
UML
对于适配模式有两种形式的实现:1、使用继承;2、使用委托,即持有一个适配的对象
使用场景
- 需要使用现有的类,而此类的接口不符合系统的需要
- 需要要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口
- 通过接口转换,将一个类插入另一个类系中
- 需要使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口(仅对象适配)
优点
- 更好的复用性
系统需要使用现有的类,而此类的接口不符合系统的需要,那么通过使用适配器模式可以使这些功能得到更好的复用。 - 更好的扩展性
在实现适配器的功能时,可以调用自己开发的功能,从而扩展系统的功能:可以让任何两个没有关联的类一起运行;灵活性好;提高了类的复用
缺点
- 过多地使用适配器,会让系统非常零乱,不易整体进行把握
- 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类
代码示例
按照上面的分类一个个演示
类的适配器
比如上个世纪的电视,基本只能看电视,现在的多媒体电视可以干很多事情,比如玩游戏等~,但看电视的功能没有变化,我们只需要实现玩游戏的相关调用逻辑即可~
有几个组成部分:待适配类,目标接口、适配器、测试类
package com.designpattern.adapter;
public class TV {
public void watchTV() {
System.out.println("watch television");
}
}
定义新接口,包含待适配来类中的方法(同名)
package com.designpattern.adapter;
public interface MultimediaTV {
public void watchTV();
public void playGame();
}
要点:继承待适配类并实现目标接口,覆盖新定义的接口方法~
package com.designpattern.adapter;
public class AdapterClass extends TV implements MultimediaTV {
@Override
public void playGame() {
// TODO Auto-generated method stub
System.err.println("play game");
}
}
package com.designpattern.adapter;
public class TestMain {
public static void main(String[] args) {
MultimediaTV multimediaTV = new AdapterClass();
multimediaTV.watchTV();
multimediaTV.playGame();
}
}
watch television
play game
对象适配器
对象适配器,相对于类适配器不继承待适配的类,而是持有待适配类的实例,来解决兼容性
package com.designpattern.adapter;
public class TV {
public void watchTV() {
System.out.println("watch television");
}
}
定义新接口(与类适配不同,这里的方法名可以自定义,可以不同名,因为在这里会调用对象的方法)
package com.designpattern.adapter;
public interface MultimediaTV {
public void watchTV();
public void playGame();
}
package com.designpattern.adapter;
public class AdapterObject implements MultimediaTV {
private TV tv;
public AdapterObject(TV tv) {
// TODO Auto-generated constructor stub
this.tv=tv;
}
@Override
public void watchTV() {
// TODO Auto-generated method stub
tv.watchTV();
}
@Override
public void playGame() {
// TODO Auto-generated method stub
System.err.println("play game in AdapterObject");
}
}
package com.designpattern.adapter;
public class TestMainObject {
public static void main(String[] args) {
TV tv = new TV();
MultimediaTV multimediaTV = new AdapterObject(tv);
multimediaTV.watchTV();
multimediaTV.playGame();
}
}
接口适配器
解决同一个接口的多个实现之间的重复代码(或者不必要的代码)。可以同一个一个抽象类实现所有未实现的方法,然后使用时继承该抽象类,覆盖相应的方法,达到减少不必要的代码。
比如还以多媒体电视为例
多媒体电视有多个品牌,抽象出来一个公共部分,使用一个抽象电视类实现所有多媒体电视定义的接口。在定义具体电视类时,继承该抽象类,覆盖相应的方法。
package com.designpattern.adapter;
public interface MediaTV {
public void setShap(String shap);
public void watchTV();
public void playGame();
public void surfInternet();
public void shopping();
}
package com.designpattern.adapter;
public class AbstractTV implements MediaTV {
@Override
public void watchTV() {
// TODO Auto-generated method stub
System.err.println("watch TV");
}
@Override
public void playGame() {
// TODO Auto-generated method stub
System.err.println("play Game");
}
@Override
public void surfInternet() {
// TODO Auto-generated method stub
System.err.println("surf the Internet");
}
@Override
public void shopping() {
// TODO Auto-generated method stub
System.err.println("shopping");
}
@Override
public void setShap(String shap) {
// TODO Auto-generated method stub
System.err.println("tv shap:"+shap);
}
}
package com.designpattern.adapter;
public class Letv extends AbstractTV{
@Override
public void setShap(String shap) {
System.err.println("set Letv shap:"+shap);
}
}
package com.designpattern.adapter;
public class PandaTv extends AbstractTV{
@Override
public void shopping() {
System.err.println("nonsupport");
}
}
package com.designpattern.adapter;
public class TestMainIntf {
public static void main(String[] args) {
AbstractTV letv = new Letv();
AbstractTV pandatv = new PandaTv();
letv.watchTV();
letv.playGame();
letv.setShap("方形的");
letv.surfInternet();
letv.shopping();
System.err.println();
pandatv.watchTV();
pandatv.playGame();
pandatv.setShap("臆想形的");
pandatv.surfInternet();
pandatv.shopping();
}
}
运行结果:
watch TV
play Game
set Letv shap:方形的
surf the Internet
shopping
watch TV
play Game
tv shap:臆想形的
surf the Internet
nonsupport
如果写过jmeter插件,里面有大量的实例,比如写http的插件有两种途径:一种实现JavaSamplerClient还有一种是继承AbstractJavaSamplerClient,其实就是使用的这种方式