设计模式总结篇系列:适配器模式(Adapter)
网上看到不少关于适配器模式的讲解,其中对于适配器模式解释的过于专业,一时不是特别理解适配器模式到底是用来干嘛的,具体的适用场景在哪,其最精髓的地方到底在哪。
本文结合自己的理解,阐述下对适配器模式的看法。
假设系统存在一个现有的类UserInfo:
class UserInfo {
private Map<String, String> userBaseInfo;
public Map getUserBaseInfo() {
return userBaseInfo;
}
public void setUserBaseInfo(Map<String, String> userBaseInfo) {
this.userBaseInfo = userBaseInfo;
}
}
客户端可以通过如下方式set、get员工基本信息:
public class AdapterTest {
public static void main(String[] args) {
UserInfo oui = new UserInfo();
Map<String, String> inUserInfo = new HashMap<String, String>() {
{
put("name", "corn");
put("telNumber", "170xxxxxxxx");
}
};
oui.setUserBaseInfo(inUserInfo);
// 原有取得员工基本信息的方式
Map<String, String> outUserInfo = oui.getUserBaseInfo();
String name = outUserInfo.get("name");
String telNumber = outUserInfo.get("telNumber");
}
}
有一天,基于某种原因(也许你看着这种取数据的方式不太爽,也许是系统间数据交换的原因等),你需要按照如下接口的方式取数据:
目标员工接口:
interface UserInterface {
public String getName();
public String getTelNumber();
}
那么,现在的问题是,如何将一个既定的类转换成按照目标接口的所期望的行为形式呢?
具体怎样实现呢,可以通过如下方式进行:
class UserAdapter extends UserInfo implements UserInterface {
@Override
public String getName() {
return (String) super.getUserBaseInfo().get("name");
}
@Override
public String getTelNumber() {
return (String) super.getUserBaseInfo().get("telNumber");
}
}
从上面的UserAdapter类定义中我们发现,UserAdapter不仅实现了UserInterface接口,同时还继承了UserInfo类。在实现接口的getName()和getTelNumber()方法中,分别调用了UserInfo类中的相应方法并取得结果。由此可以满足需求。在上述定义中,按照UserInterface、UserInfo和UserAdapter在场景中的目的不同,可以具体划分成如下角色:
UserInterface:目标角色——目标接口,系统所期待实现的目标;
UserInfo:源角色——当前已经存在的原有的实现类,即将被适配的类;
UserAdapter:适配器角色——将原有实现装换为目标接口的实现。
简单点说,适配器模式是指:定义一个类,将一个已经存在的类,转换成目标接口所期望的行为形式。
在具体的实现过程中,又可以基于其实现层次是类层次还是对象层次,将其分为类适配器和对象适配器。如上所写的是类适配器。
对象适配器使用组合代替继承,将源角色视为适配器角色的属性:
class UserAdapter implements UserInterface {
private UserInfo userInfo;
public UserAdapter(){
}
public UserAdapter(UserInfo userInfo){
this.userInfo = userInfo;
}
@Override
public String getName() {
return (String) userInfo.getUserBaseInfo().get("name");
}
@Override
public String getTelNumber() {
return (String) userInfo.getUserBaseInfo().get("telNumber");
}
}
总体而言:适配器模式是指定义一个适配器类,将一个已经存在的类,转换成目标接口所期望的行为形式。同时,一般来说,基于更多的推荐使用组合而不是继承,因此,对象适配器可能使用更多。
设计模式总结篇系列:适配器模式(Adapter)的更多相关文章
- 设计模式(五)适配器模式Adapter(结构型)
设计模式(五)适配器模式Adapter(结构型) 1. 概述: 接口的改变,是一个需要程序员们必须(虽然很不情愿)接受和处理的普遍问题.程序提供者们修改他们的代码;系统库被修正;各种程序语言以及相 ...
- 设计模式总结篇系列:原型模式(Prototype)
首先对原型模式进行一个简单概念说明:通过一个已经存在的对象,复制出更多的具有与此对象具有相同类型的新的对象. 在理解Java原型模式之前,首先需要理解Java中的一个概念:复制/克隆. 在博文< ...
- 设计模式(三)-- 适配器模式(Adapter)
适配器模式(Adapter) 考虑一个记录日志的应用,由于用户对日志记录的要求很高,使得开发人员不能简单地采用一些已有的日志工具或日志框架来满足用户的要求,而需要按照用户的要求重新开发新的日志管理系统 ...
- 设计模式总结篇系列:享元模式(Flyweight)
我们都知道,Java中的String类具有如下特性:String是一个不可变类,当直通过用字符串方式使用String对象时,Jvm实际上在内存中只存有一份,且存在字符串常量池中.当对字符串直接进行修改 ...
- 设计模式之十三:适配器模式(Adapter)
适配器模式: 将一个类的接口转换成另外一个期望的类的接口.适配器同意接口互不兼容的类一起工作. Convert the interface of a class into another interf ...
- 设计模式总结篇系列:抽象工厂模式(Abstract Factory)
在上一篇的工厂方法模式中,通过一个公用的类对其他具有相同特性(实现相同接口或继承同一父类)的类的对象进行创建.随之带来的问题在于:当新定义了一个具有相同特性的类时,需要修改工厂类.这与设计模式中的开闭 ...
- 设计模式总结篇系列:策略模式(Strategy)
前面的博文中分别介绍了Java设计模式中的创建型模式和结构型模式.从本文开始,将分别介绍设计模式中的第三大类,行为型模式.首先我们了解下分为此三大类的依据. 创建型模式:主要侧重于对象的创建过程: 结 ...
- 设计模式总结篇系列:桥接模式(Bridge)
在实际类设计过程中,有时会遇到此类情况:由于实际的需要,某个类具有两个或两个以上的维度变化,如果利用继承将每种可能的变化情况都定义成一个类,一是会导致类膨胀的问题,二是以后不太好维护和并且违背类的设计 ...
- 设计模式总结篇系列:代理模式(Proxy)
时代在发展,我们发现,现在不少明星都开始进行微访谈之类的,有越来越多的参与捐赠等.新的一天开始了,首先看下新的一天的日程安排: interface Schedule{ public void weiT ...
随机推荐
- Fio测试工具参数
以随机读为例:fio -ioengine=libaio -group_reporting -direct=1 -name=testsda -numjobs=1 --time_based --runti ...
- IDEA+Tomcat+Maven+SpringMVC基于Java注解配置web工程
1.在IDEA中新建Maven工程,使用archetype. 2.添加Maven依赖 <dependencies> <dependency> <groupId>ju ...
- 《SpringMVC从入门到放肆》十四、SpringMVC分组数据校验
上一篇我们学习了数据校验,但是在实际项目中,还是有些不够灵活,今天我们就来继续学习一种更灵活的数据校验方法——分组数据校验. 一.什么是分组校验 校验规则是定义在实体中的,而同一个实体可以被多个Con ...
- 动态sql语句,非存储过程,如何判断某条数据是否存在,如果不存在就添加一条
已知一个表 table 里面有两个字段 A1 和 A2 如何用动态语句 判断 A1 = A , A2=B 的数据是否存在,如果不存在,就添加一条数据, A1 = A , A2 = B INSERT ...
- socket 套接字服务器端和客户端发送信息
import socket import threading host='' port=6889 def cilenThred(conn,addr): print("成功接受客户端{}的连接 ...
- 接口自动化集成到jenkins(Java+testng+maven+git)
一jenkins启动命令:jenkins 查看端口号: 1.lsof -i:端口号 2.netstat -tunlp|grep 端口号 二: 登录:http://localhost:8080 输入:u ...
- QEMU KVM Libvirt手册(10):Managing Virtual Machines with libvirt
libvirt is a library that provides a common API for managing popular virtualization solutions, among ...
- 如何修改image文件
方法一:mount成为一个loop device 参考http://smilejay.com/2012/08/mount-an-image-file/ 方法一:找出分区开始的开始位置,使用mount命 ...
- URL跳转与webview安全浅谈
URL跳转与webview安全浅谈 我博客的两篇文章拼接在一起所以可能看起来有些乱 起因 在一次测试中我用burpsuite搜索了关键词url找到了某处url我测试了一下发现waf拦截了指向外域的请求 ...
- [Swift]LeetCode105. 从前序与中序遍历序列构造二叉树 | Construct Binary Tree from Preorder and Inorder Traversal
Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that ...