6.适配器模式
它可以将一个类的接口转换成客户希望的另一个接口,主要目的是充当两个不同接口之间的桥梁,使得原本接口不兼容的类能够一起工作。
需求
【设计模式专题之适配器模式】6. 扩展坞
题目描述
- 小明购买了一台新电脑,该电脑使用 TypeC 接口,他已经有了一个USB接口的充电器和数据线,为了确保新电脑可以使用现有的USB接口充电器和数据线,他购买了一个TypeC到USB的扩展坞。
- 请你使用适配器模式设计并实现这个扩展坞系统,确保小明的新电脑既可以通过扩展坞使用现有的USB接口充电线和数据线,也可以使用TypeC接口充电。
输入描述
- 题目包含多行输入,第一行输入一个数字 N (1 < N <= 20),表示后面有N组测试数据。
- 之后N行都是一个整数,1表示使用电脑本身的TypeC接口,2表示使用扩展坞的USB接口充电。
输入示例
3
1
2
1
输出示例
TypeC
USB Adapter
TypeC
什么是适配器
适配器模式Adapter
是一种结构型设计模式,它可以将一个类的接口转换成客户希望的另一个接口,主要目的是充当两个不同接口之间的桥梁,使得原本接口不兼容的类能够一起工作。
基本结构
适配器模式分为以下几个基本角色:
可以把适配器模式理解成拓展坞,起到转接的作用,原有的接口是USB,但是客户端需要使用
type-c
, 便使用拓展坞提供一个type-c
接口给客户端使用
- 目标接口
Target
: 客户端希望使用的接口 - 适配器类
Adapter
: 实现客户端使用的目标接口,持有一个需要适配的类实例。 - 被适配者
Adaptee
: 需要被适配的类
这样,客户端就可以使用目标接口,而不需要对原来的Adaptee
进行修改,Adapter
起到一个转接扩展的作用。
基本实现
// 目标接口
interface Target {
void request();
}
// 被适配者类
class Adaptee {
void specificRequest() {
System.out.println("Specific request");
}
}
// 适配器类
class Adapter implements Target {
// 持有一个被适配者实例
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
// 调用被适配者类的方法
adaptee.specificRequest();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Target target = new Adapter(new Adaptee());
target.request();
}
}
应用场景
在开发过程中,适配器模式往往扮演者“补救”和“扩展”的角色:
-
当使用一个已经存在的类,但是它的接口与你的代码不兼容时,可以使用适配器模式。
-
在系统扩展阶段需要增加新的类时,并且类的接口和系统现有的类不一致时,可以使用适配器模式。
使用适配器模式可以将客户端代码与具体的类解耦,客户端不需要知道被适配者的细节,客户端代码也不需要修改,这使得它具有良好的扩展性,但是这也势必导致系统变得更加复杂。
具体来说,适配器模式有着以下应用:
-
不同的项目和库可能使用不同的日志框架,不同的日志框架提供的API也不同,因此引入了适配器模式使得不同的API适配为统一接口。
-
Spring MVC中,
HandlerAdapter
接口是适配器模式的一种应用。它负责将处理器(Handler)适配到框架中,使得不同类型的处理器能够统一处理请求。 -
在
.NET
中,DataAdapter
用于在数据源(如数据库)和DataSet
之间建立适配器,将数据从数据源适配到DataSet
中,以便在.NET应用程序中使用。
本题代码
// 测试程序
import java.util.Scanner;
// USB 接口
interface USB {
void charge();
}
// TypeC 接口
interface TypeC {
void chargeWithTypeC();
}
// 适配器类
class TypeCAdapter implements USB {
private TypeC typeC;
public TypeCAdapter(TypeC typeC) {
this.typeC = typeC;
}
@Override
public void charge() {
typeC.chargeWithTypeC();
}
}
// 新电脑类,使用 TypeC 接口
class NewComputer implements TypeC {
@Override
public void chargeWithTypeC() {
System.out.println("TypeC");
}
}
// 适配器充电器类,使用 USB 接口
class AdapterCharger implements USB {
@Override
public void charge() {
System.out.println("USB Adapter");
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取连接次数
int N = scanner.nextInt();
scanner.nextLine(); // 消耗换行符
for (int i = 0; i < N; i++) {
// 读取用户选择
int choice = scanner.nextInt();
// 根据用户的选择创建相应对象
if (choice == 1) {
TypeC newComputer = new NewComputer();
newComputer.chargeWithTypeC();
} else if (choice == 2) {
USB usbAdapter = new AdapterCharger();
usbAdapter.charge();
}
}
scanner.close();
}
}
其他语言代码
Java
类适配器模式代码:
import java.util.*;
// 定义计算机端口接口
interface ComputerPort {
void connect();
}
// TypeC端口类实现ComputerPort接口
class TypeCPort implements ComputerPort {
@Override
public void connect() {
System.out.println("TypeC");
}
}
// USB设备类
class USBDevice {
public void connectUSB() {
System.out.println("USB Adapter");
}
}
// TypeC到USB适配器类
class TypeCToUSBAdapter extends USBDevice implements ComputerPort {
@Override
public void connect() {
super.connectUSB();
}
}
public class Main{
public static void main(String[] args) {
Scanner inputScanner = new Scanner(System.in);
Map<Integer, ComputerPort> connectionModes = new HashMap<>();
connectionModes.put(1, new TypeCPort());
connectionModes.put(2, new TypeCToUSBAdapter());
int totalConnections = inputScanner.nextInt();
inputScanner.nextLine();
while (inputScanner.hasNextInt()) {
int choice = inputScanner.nextInt();
connectionModes.getOrDefault(choice, () -> System.out.println("")).connect();
}
inputScanner.close();
}
}
C++
#include <iostream>
// USB 接口
class USB {
public:
virtual void charge() = 0;
};
// TypeC 接口
class TypeC {
public:
virtual void chargeWithTypeC() = 0;
};
// 适配器类
class TypeCAdapter : public USB {
private:
TypeC* typeC;
public:
TypeCAdapter(TypeC* typeC) : typeC(typeC) {}
void charge() override {
typeC->chargeWithTypeC();
}
};
// 新电脑类,使用 TypeC 接口
class NewComputer : public TypeC {
public:
void chargeWithTypeC() override {
std::cout << "TypeC" << std::endl;
}
};
// 适配器充电器类,使用 USB 接口
class AdapterCharger : public USB {
public:
void charge() override {
std::cout << "USB Adapter" << std::endl;
}
};
int main() {
// 读取连接次数
int N;
std::cin >> N;
std::cin.ignore(); // 消耗换行符
for (int i = 0; i < N; i++) {
// 读取用户选择
int choice;
std::cin >> choice;
// 根据用户的选择创建相应对象
if (choice == 1) {
TypeC* newComputer = new NewComputer();
newComputer->chargeWithTypeC();
delete newComputer;
} else if (choice == 2) {
USB* usbAdapter = new AdapterCharger();
usbAdapter->charge();
delete usbAdapter;
}
}
return 0;
}
Python
# USB 接口
class USB:
def charge(self):
pass
# TypeC 接口
class TypeC:
def charge_with_type_c(self):
pass
# 适配器类
class TypeCAdapter(USB):
def __init__(self, type_c):
self.type_c = type_c
def charge(self):
self.type_c.charge_with_type_c()
# 新电脑类,使用 TypeC 接口
class NewComputer(TypeC):
def charge_with_type_c(self):
print("TypeC")
# 适配器充电器类,使用 USB 接口
class AdapterCharger(USB):
def charge(self):
print("USB Adapter")
if __name__ == "__main__":
# 读取连接次数
N = int(input())
for _ in range(N):
# 读取用户选择
choice = int(input())
# 根据用户的选择创建相应对象
if choice == 1:
new_computer = NewComputer()
new_computer.charge_with_type_c()
elif choice == 2:
usb_adapter = AdapterCharger()
usb_adapter.charge()
Go
package main
import "fmt"
// USB 接口
type USB interface {
charge()
}
// TypeC 接口
type TypeC interface {
chargeWithTypeC()
}
// 适配器类
type TypeCAdapter struct {
typeC TypeC
}
func (tca *TypeCAdapter) charge() {
tca.typeC.chargeWithTypeC()
}
// 新电脑类,使用 TypeC 接口
type NewComputer struct{}
func (nc *NewComputer) chargeWithTypeC() {
fmt.Println("TypeC")
}
// 适配器充电器类,使用 USB 接口
type AdapterCharger struct{}
func (ac *AdapterCharger) charge() {
fmt.Println("USB Adapter")
}
func main() {
var N int
fmt.Scan(&N) // 读取连接次数
for i := 0; i < N; i++ {
var choice int
fmt.Scan(&choice) // 读取用户选择
// 根据用户的选择创建相应对象
if choice == 1 {
newComputer := &NewComputer{}
adapter := &TypeCAdapter{typeC: newComputer}
adapter.charge()
} else if choice == 2 {
usbAdapter := &AdapterCharger{}
usbAdapter.charge()
}
}
}