什么是适配器模式
将一客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作,主要目的是兼容性。
适配器模式可以细分为类适配器模式,对象适配器模式和接口适配器模式。
结构
- 目标接口(Target Interface):当前系统业务所期待的接口,它可以是抽象类或接口。
- 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
- 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
类适配器模式
实现方式:定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件
UML类图
代码理解
// 目标接口
interface Target {
void request();
}
// 适配者类
class Adaptee {
public void specificRequest() {
System.out.println("特定请求");
}
}
// 类适配器
class ClassAdapter extends Adaptee implements Target {
public void request() {
specificRequest();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request();
}
}
对象适配器模式
实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。
- 根据“合成复用原则”,在系统中尽量使用关联关系(聚合)来替代继承关系。
- 对象适配器模式是适配器模式常用的一种
UML类图
代码理解
// 目标接口
interface Target {
void request();
}
// 适配者类
class Adaptee {
public void specificRequest() {
System.out.println("特定请求");
}
}
// 对象适配器
class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
public void request() {
adaptee.specificRequest();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之不可用。
接口适配器模式
- 核心思路:当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。
- 适用于一个接口不想使用其所有的方法的情况。
UML类图
代码理解
public interface ActionListener {
void onClick();
void onDoubleClick();
void onRightClick();
}
public abstract class ActionAdapter implements ActionListener {
@Override
public void onClick() {
// 默认实现为空操作
}
@Override
public void onDoubleClick() {
// 默认实现为空操作
}
@Override
public void onRightClick() {
// 默认实现为空操作
}
}
public class MouseHandler extends ActionAdapter {
@Override
public void onClick() {
System.out.println("Mouse clicked!");
}
// 选择不实现onDoubleClick和onRightClick
}
public class AnotherHandler extends ActionAdapter {
@Override
public void onDoubleClick() {
System.out.println("Double click detected!");
}
@Override
public void onRightClick() {
System.out.println("Right click detected!");
}
}
public class Main {
public static void main(String[] args) {
ActionListener handler1 = new MouseHandler();
ActionListener handler2 = new AnotherHandler();
handler1.onClick(); // 输出: Mouse clicked!
handler2.onDoubleClick(); // 输出: Double click detected!
handler2.onRightClick(); // 输出: Right click detected!
}
}
使用场景
- 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。
案例分析
SpringMVC框架
在Spring MVC框架中,适配器模式被用来处理不同类型的控制器(Controller)方法。Spring MVC通过HandlerAdapter接口和它的实现类来支持多种不同的控制器方法风格。这种方式允许Spring MVC框架能够灵活地调用各种类型的控制器方法,而不需要直接硬编码这些调用逻辑。
为什么使用适配器模式
- 灵活性:允许Spring MVC框架处理不同类型的方法签名,比如返回一个视图名称、返回一个模型对象、返回一个ResponseEntity等。
- 可扩展性:开发者可以自定义HandlerAdapter实现来处理特定的请求类型或控制器方法风格。
Spring MVC中的适配器模式
- HandlerAdapter接口: HandlerAdapter接口定义了处理控制器方法的核心行为。它主要包含以下几个方法:
-
- boolean supports(Object handler):判断给定的处理器是否可以由该适配器处理。
- ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler):实际处理请求并返回结果。
- 内置的HandlerAdapter实现: Spring MVC提供了几个默认的HandlerAdapter实现,用于处理不同类型的控制器方法:
-
- RequestMappingHandlerAdapter:处理带有@RequestMapping注解的方法。
- SimpleControllerHandlerAdapter:处理实现了Controller接口的类。
- HttpRequestHandlerAdapter:处理实现了HttpRequestHandler接口的类。
- DispatcherServlet如何使用适配器: 当一个请求到达时,DispatcherServlet会尝试找到合适的HandlerAdapter来处理对应的控制器。它是通过遍历所有注册的HandlerAdapter实例,并调用每个适配器的supports方法来确定哪个适配器适合当前的控制器。一旦找到了合适的适配器,DispatcherServlet就会调用该适配器的handle方法来处理请求。
示例代码
// 定义一个简单的控制器
@Controller
public class MyController {
@RequestMapping("/hello")
public String sayHello() {
return "hello";
}
}
// 配置Spring MVC
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// 可以在这里添加自定义的HandlerAdapter
@Override
public void configureHandlerAdapters(List<HandlerAdapter> adapters) {
adapters.add(new MyCustomHandlerAdapter());
}
// 自定义的HandlerAdapter
public static class MyCustomHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
// 判断是否支持这个handler
return handler instanceof MySpecialController;
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 处理请求
return new ModelAndView("viewName", "modelKey", "modelValue");
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
}
}
在这个例子中,MyCustomHandlerAdapter是一个自定义的适配器,它只处理实现了MySpecialController接口的控制器。