当前位置: 首页 > news >正文

结合JDK源码看设计模式——适配器模式

定义:
  将一个类的接口转换成客户期望的另外一个接口(重点理解适配的这两个字),使得接口不兼容的类可以一起工作
适用场景:

  1. 已经存在的类,它的方法和需求不匹配的时候
  2. 在软件维护阶段考虑的设计模式

详解
  首先来从生活中的常见场景来看,一个电源插座输出都是220V,而我们一些电子设备,比如手机,MP3,MP4,所需要的电压不一样,也不可能直接就是220接上,这就需要一个中间的转换器,每个厂家不同,对应的充电线也有可能不同。这个不同的充电线就可以理解为一个适配器。而220V的输出电压可以看做是我们做好的一套系统,只不过对应到不同客户就需要不同的适配器。下面分为三个模块来讲解

1.类适配器

输出的电压类

public class AC220 {
public int outputAC220V(){
int output = 220;
System.out.println("输出交流电"+output+"V");
return output;
}
}

5V电压接口

public interface DC5 {
int outputDC5V();
}

适配器类

public class PowerAdapter extends AC220 implements DC5{

@Override
public int outputDC5V() {
int adapterInput=outputAC220V();
int adapterOutput = adapterInput/44;
System.out.println("使用PowerAdapter输入AC:"+adapterInput+"V"+"输出DC:"+adapterOutput+"V");
return adapterOutput;
}
}

测试代码:

public class Test {

public static void main(String[] args) {
DC5 dc5=new PowerAdapter();
System.out.println(dc5.outputDC5V());

}
}

输出结果

 

  可能很多人看到这就会问,这不就是装饰者模式吗?这个不就相当于扩展功能吗,其实呢这两个模式所处的阶段不同,一个是在软件设计的时候需要考虑的,这个呢是在软件后续维护的时候所考虑的。第二个其实就是最大的区别:装饰者和被装饰者之间的接口相同,而适配器和被适配器之间的接口是不相同的(当然有些特殊情况是相同的)。假如我是另外一个电子设备,我需要3V的接口,那么我们只需要再定义一个DC3接口,修改PowerAdapter里面的适配方法。但是我这个厂家并不再需要5V的接口了,所以我这边有的其实只是DC3不是DC5.看看现在的UML类图

  还是和装饰者有区别的,当然你要是通过装饰者来实现上述功能一样能实现
2.对象适配器
  上述UML图中我们可以看出AC220和PowerAdapter连接太过紧密了,如果我们这是个很复杂的系统,那这样做无疑让我们的适配器加载会很慢,毕竟子类要想初始化完,就必须要父类先初始化完,所以我们可以不用继承,而使用成员变量的方式来解决,即修改PowerAdapter的代码

public class PowerAdapter implements DC5,DC3{
private AC220 ac220=new AC220();
private int adapterInput=ac220.outputAC220V();
@Override
public int outputDC5V() {

int adapterOutput = adapterInput/44;
System.out.println("使用PowerAdapter输入AC:"+adapterInput+"V"+"输出DC:"+adapterOutput+"V");
return adapterOutput;
}

@Override
public int outputDC3V() {
int adapterOutput=adapterInput/73;
System.out.println("使用PowerAdapter输入AC:"+adapterInput+"V"+"输出DC:"+adapterOutput+"V");
return adapterOutput;
}
}

UML类图

  从继承变成了组合,这就是对象适配
3.JDK解读
  XmlAdapter就是一个最典型的适配器,下面我们来看代码具体分析

定义一个学生类,将学生类序列化成xml文件

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.Date;

@XmlType(propOrder={"id","name","birthDay"}) //指定序列成的xml节点顺序
@XmlAccessorType(value=XmlAccessType.FIELD) //访问类型改为字段
@XmlRootElement
public class Student {
@XmlElement
private String id;
@XmlElement
private String name;
@XmlJavaTypeAdapter(value=DateAdapter.class)
@XmlElement
private Date birthDay;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Date getBirthDay() {
return birthDay;
}

public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}

@Override
public String toString() {
return "Student{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", birthDay=" + birthDay +
'}';
}
}

Date适配器

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class DateAdapter extends XmlAdapter<String, Date> {
//反序列化成日期对象Date
@Override
public Date unmarshal(String str) throws Exception {
SimpleDateFormat format = getSimpleDateFormat("yyyy-MM HH:mm:ss");
return str==null ? null:format.parse(str);
}
//序列化成xmL
@Override
public String marshal(Date date) throws Exception {
SimpleDateFormat format = getSimpleDateFormat("yyyy-MM HH:mm:ss");
return date==null ? "":format.format(date);
}
private SimpleDateFormat getSimpleDateFormat(String pattern){
SimpleDateFormat format = new SimpleDateFormat(pattern);
return format;
}
}

编写测试类

import javax.xml.bind.JAXBContext;

import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.*;
import java.util.Date;

public class Test {

public static void main(String[] args) {
DateAdapter da=new DateAdapter();
Student stu = new Student();
stu.setId("1");
stu.setName("方块人");
stu.setBirthDay(new Date());
try {
JAXBContext context = JAXBContext.newInstance(Student.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
//marshaller.marshal(stu, System.out);
StringWriter writer = new StringWriter();
marshaller.marshal(stu, writer);
System.out.println(writer.toString());
//反序列化
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader reader = new StringReader(writer.toString());
Student stu2 = (Student) unmarshaller.unmarshal(reader);

} catch (Exception e) {
e.getMessage();
e.printStackTrace();
}
}
}

输出结果:

  注意看birthDay这个Date类型,我们已经在转化成xml文件的时候将日期格式变化成功,如果是没有进行日期适配器转换的话的输出结果是

  这样就不是我们想要的格式

XmlAdapter源码:

public abstract class XmlAdapter<ValueType,BoundType> {

/**
* Do-nothing constructor for the derived classes.
*/
protected XmlAdapter() {}

/**
* Convert a value type to a bound type.
*
* @param v
* The value to be converted. Can be null.
* @throws Exception
* if there's an error during the conversion. The caller is responsible for
* reporting the error to the user through {@link javax.xml.bind.ValidationEventHandler}.
*/
public abstract BoundType unmarshal(ValueType v) throws Exception;

/**
* Convert a bound type to a value type.
*
* @param v
* The value to be convereted. Can be null.
* @throws Exception
* if there's an error during the conversion. The caller is responsible for
* reporting the error to the user through {@link javax.xml.bind.ValidationEventHandler}.
*/
public abstract ValueType marshal(BoundType v) throws Exception;
}

  有两个方法需要实现,一个是反序列化,另外一个是序列化。相信你看懂了适配器模式之后,也能理解这个类中的方法含义

总结:

  适配器模式更多的是提供不同接口给不同的厂家,适配器我们知道怎么实现之后,更多的是在适用场景中去思考。这样就会对适配器模式有更加深刻的理解。

转载于:https://www.cnblogs.com/Cubemen/p/10661419.html

相关文章:

  • SpringBoot 整合Mybatis
  • 1023. Camelcase Matching驼峰式匹配
  • Linux基础命令试题——第二周
  • 基于SimpleChain Beta的跨链交互与持续稳态思考
  • 一位6年老Android面经总结
  • PESCMS Ticket 客服工单系统 v1.2.5 发布
  • mysql补
  • JS中常遇到的浏览器兼容问题和解决方法
  • 百度联合清华发布国内首个基于AI实践的产业智能化白皮书
  • 防护等级高的才能适合在任何环境中应用
  • 只想着一直调用一直爽, 那API凭证泄漏风险如何破?
  • 一句话,讲清楚java泛型的本质(非类型擦除)
  • JSP介绍
  • 团队作业第五次—项目系统设计与数据库设计
  • Gson自动解析json
  • 深入了解以太坊
  • 《深入 React 技术栈》
  • AHK 中 = 和 == 等比较运算符的用法
  • avalon2.2的VM生成过程
  • dva中组件的懒加载
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • Javascript 原型链
  • Java多线程(4):使用线程池执行定时任务
  • JS变量作用域
  • learning koa2.x
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • log4j2输出到kafka
  • Object.assign方法不能实现深复制
  • Otto开发初探——微服务依赖管理新利器
  • python大佬养成计划----difflib模块
  • React系列之 Redux 架构模式
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • 安装python包到指定虚拟环境
  • 从输入URL到页面加载发生了什么
  • 关于 Cirru Editor 存储格式
  • 计算机在识别图像时“看到”了什么?
  • 前端攻城师
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 线上 python http server profile 实践
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 用Canvas画一棵二叉树
  • 再次简单明了总结flex布局,一看就懂...
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转)EXC_BREAKPOINT僵尸错误
  • (转)linux下的时间函数使用
  • **PHP分步表单提交思路(分页表单提交)
  • .h头文件 .lib动态链接库文件 .dll 动态链接库