基本介绍 – 加个”适配器“以便于复用
- 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)
- 适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。
- 主要分类:类适配器模式、对象适配器模式
举例:
可以先想象下适配器就是笔记本充电器,被适配对象就是220V电压,真正需要的就是笔记本的充电电压(比如是12V),充电器起到适配的作用,就是将220V适配成12V我们需要的电压。
类适配器(使用继承)
示例程序:
一段将输入的字符两边加上()或者**的简单程序。
类图:
Banner类:中有一些功能类 (通常来自第三方或遗留系统)。 客户端与其接口不兼容, 因此无法直接调用其功能。
//被适配的类(220V电压)
public class Banner {
private String string;
public Banner(String string) {
this.string = string;
}
//字符串两边加括号
public void showWithParen(){
System.out.println("(" + string + ")");
}
//字符串两边加*号
public void showWithAster(){
System.out.println("*" + string + "*");
}
}
Print接口
//负责定义所需的方法(12V电压)
public interface Print {
//弱化字符串显示(加括号),只是不一样的叫法,但就是叫法不一样,需求变了就要适配以前的接口
void printWeak();
//强化字符串显示(加*号)
void printStrong();
}
PrintBanner类:
- 适配器 (Adapter) 是一个可以同时与Print和Banner交互的类,适配器接受Print通过适配器接口发起的调用, 并将其转换为适用于被封装Banner对象的调用。
- 客户端代码(Main)只需通过接口与适配器交互即可, 无需与具体的适配器类耦合。 因此, 你可以向程序中添加新类型的适配器而无需修改已有代码。 这在服务类的接口被更改或替换时很有用: 你无需修改客户端代码就可以创建新的适配器类。
//适配器(适配作用)
public class PrintBanner extends Banner implements Print {
public PrintBanner(String string) {
super(string);
}
//就是新的方法嵌套旧的方法,但实际开发中肯定加逻辑,
@Override
public void printWeak() {
showWithParen();
}
//
@Override
public void printStrong() {
showWithAster();
}
}
Mian类
public class Main {
public static void main(String[] args) {
Print banner = new PrintBanner("Hello");
banner.printStrong();
banner.printWeak();
}
}
总结:
- Java是单继承机制,所以类适配器需要继承Banner类这一点算是一个缺点, 因为这要求Print必须是接口,有一定局限性;
- Banner类的方法在Adapter(适配器)中都会暴露出来,也增加了使用的成本。
- 由于其继承了Banner类,所以它可以根据需求重写Banner类的方法,使得Adapter的灵
活性增强了。
对象适配器(使用委托)
对象适配器模式介绍
- 我们假设Print类不是接口,而是类,java无法同时继承两个类,可以让PrintBanner类不继承Banner,而是持有Banner类的实例,以解决兼容性的问题。
- 根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系。
- 对象适配器模式是适配器模式常用的一种
类图:
Print类
public abstract class Print {
public abstract void printWeak();
public abstract void printStrong();
}
PrintBanner:
- 它在实现Print接口的同时封装了Banner对象。
public class PrintBanner extends Print{
private Banner banner;
public PrintBanner(String string) {
this.banner = new Banner(string);
}
@Override
public void printWeak() {
banner.showWithParen();
}
@Override
public void printStrong() {
banner.showWithAster();
}
}
总结:
- 对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。根据合成复用原则,使用组合替代继承, 所以它解决了类适配器必须继承Banner的局限性问题。
- 使用成本更低,更灵活。
适配器模式中的登场角色
- Target(对象)该角色负责定义所需的方法。以之前的例子,笔记本所需的电压12V,示例程序中,Print担任此角色
- Adaptee(被适配)例子中220V电压就是被适配的对象,示例程序中,Banner担任此角色
- Adapter(适配)适配器模式的灵魂,例子中,Adapter就是将220V转为12V,示例程序中,PrintBanner担任此角色
类适配器的类图
对象适配器的类图
适用场景
- 当你希望使用某个类, 但是其接口与其他代码不兼容时, 可以使用适配器类。
- 适配器模式允许你创建一个中间层类, 其可作为代码与遗留类、 第三方类或提供怪异接口的类之间的转换器。软件的版本升级与兼容性,新版本适配旧版本就可以使用适配器模式。
- 开发中使用到现有的类,使用适配器模式,生成新的类,现有的类一定是充分测试过,bug少,当出现bug时,大概率出现我们新的类中,问题的排查就会变得简单。使用适配器模式可以完全不改变现有代码的情况下,使现有代码适配新的接口。
优点:
- 单一职责原则_你可以将接口或数据转换代码从程序主要业务逻辑中分离。
- 开闭原则。 只要客户端代码通过客户端接口与适配器进行交互, 你就能在不修改现有客户端代码的情况下在程序中添加新类型的适配器。
缺点:
- 代码整体复杂度增加, 因为你需要新增一系列接口和类。 有时直接更改服务类使其与其他代码兼容会更简单。