设计模式的应用场景(7)--适配器模式
来源:互联网 发布:黎东方知乎 编辑:程序博客网 时间:2024/06/11 11:42
适配器模式
定义:将一个系统的接口转换成另外一种形式,从而使原来不能直接调用的接口变得可以调用。
优点
适配器模式也是一种包装模式,它与装饰模式同样具有包装的功能,此外,对象适配器模式还具有委托的意思。总的来说,适配器模式属于补偿模式,专用来在系统后期扩展、修改时使用。
缺点
过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
适配器模式应用场景
在软件开发中,也就是系统的数据和行为都正确,但接口不相符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。比如在需要对早期代码复用一些功能等应用上很有实际价值。适用场景大致包含三类:
1、已经存在的类的接口不符合我们的需求;
2、创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;
3、在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类。
下面举例说明适配器模式的使用:
接着上面的例子,内网的负责人写的代码是接收Map类型的
import java.util.HashMap;import java.util.Map;public class Application { public static void execute(HashMap map) { for (int i = 0; i < map.size(); i++) { System.out.println(map.get(i+"")); } }}
小巩基于外观模式写的接口是提供list
import java.util.List;import java.util.ArrayList;import java.util.Map;import java.util.HashMap;public class Facade { public List getEmpByOrgan(String orgId) { List list = new ArrayList(); list.add("张三"); list.add("李四"); list.add("王五"); return list; }}
那么问题来了,两边接口不一样,需要适配器
import java.util.Map;import java.util.List;import java.util.HashMap;public class ListAdapter extends HashMap{ private List list; ListAdapter(List list) { this.list = list; } public int size() { return list.size(); } public Object get(Object i) { return list.get((Integer.valueOf(i.toString())).intValue()); }}
最后,看看客户端调用代码
public class Client { public static void main(String[] argv) { Facade facade = new Facade(); ListAdapter listAdapter = new ListAdapter(facade.getEmpByOrgan("1")); Application.execute(listAdapter); }}
上面演示的是对象适配器的用法,可以看到被适配的对象是被引用的。另外一种方式是类适配器,被适配的类是以继承接口方式使用的。
下面的例子展示两种适配器的使用
考虑一个记录日志的应用,用户可能会提出要求采用文件的方式存储日志,也可能会提出存储日志到数据库的需求,这样我们可以采用适配器模式对旧的日志类进行改造,提供新的支持方式。
首先我们需要一个简单的日志对象类
public class LogBean { private String logId;//日志编号 private String opeUserId;//操作人员 public String getLogId(){ return logId; } public void setLogId(String logId){ this.logId = logId; } public String getOpeUserId(){ return opeUserId; } public void setOpeUserId(String opeUserId){ this.opeUserId = opeUserId;}public String toString(){ return "logId="+logId+",opeUserId="+opeUserId;}}
接下来定义一个操作日志文件的接口
import java.util.List;/* * 读取日志文件,从文件里面获取存储的日志列表对象 * @return 存储的日志列表对象 */public interface LogFileOperateApi { public List<LogBean> readLogFile(); /** * 写日志文件,把日志列表写出到日志文件中去 * @param list 要写到日志文件的日志列表 */ public void writeLogFile(List<LogBean> list);}
然后实现日志文件的存储和获取
import java.io.File;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.util.List;/* * 实现对日志文件的操作 */public class LogFileOperate implements LogFileOperateApi{ /* * 设置日志文件的路径和文件名称 */private String logFileName = "file.log";/* * 构造方法,传入文件的路径和名称 */public LogFileOperate(String logFilename){if(logFilename!=null){this.logFileName = logFilename;}}@Overridepublic List<LogBean> readLogFile() {// TODO Auto-generated method stubList<LogBean> list = null;ObjectInputStream oin =null;//业务代码return list;}@Overridepublic void writeLogFile(List<LogBean> list) {// TODO Auto-generated method stubFile file = new File(logFileName);ObjectOutputStream oout = null;//业务代码}}
如果这时候需要引入数据库方式,引入适配器之前,我们需要定义日志管理的操作接口
public interface LogDbOpeApi { /* * 新增日志 * @param 需要新增的日志对象 */public void createLog(LogBean logbean);}接下来就要实现适配器了,LogDbOpeApi 接口就相当于 Target 接口,LogFileOperate 就相当于 Adaptee 类import java.util.List;/* * 适配器对象,将记录日志到文件的功能适配成数据库功能 */public class LogAdapter implements LogDbOpeApi{ private LogFileOperateApi adaptee; public LogAdapter(LogFileOperateApi adaptee){ this.adaptee = adaptee; }@Overridepublic void createLog(LogBean logbean) {// TODO Auto-generated method stubList<LogBean> list = adaptee.readLogFile();list.add(logbean);adaptee.writeLogFile(list);}}
最后是客户端代码的实现
import java.util.ArrayList;import java.util.List;public class LogClient { public static void main(String[] args){ LogBean logbean = new LogBean(); logbean.setLogId("1"); logbean.setOpeUserId("michael"); List<LogBean> list = new ArrayList<LogBean>(); LogFileOperateApi logFileApi = new LogFileOperate(""); //创建操作日志的接口对象 LogDbOpeApi api = new LogAdapter(logFileApi); api.createLog(logbean); }}
下面演示累类适配器
import java.util.List;/* * 类适配器对象案例 */public class ClassAdapter extends LogFileOperate implements LogDbOpeApi{public ClassAdapter(String logFilename) {super(logFilename);// TODO Auto-generated constructor stub}@Overridepublic void createLog(LogBean logbean) {// TODO Auto-generated method stubList<LogBean> list = this.readLogFile();list.add(logbean);this.writeLogFile(list);}}
在实现中,主要是适配器的实现与以前不一样,与对象适配器实现同样的功能相比,类适配器在实现上有所改变:
需要继承 LogFileOperate 的实现,然后再实现 LogDbOpeApi 接口;
需要按照继承 LogFileOperate 的要求,提供传入文件路径和名称的构造方法;
不再需要持有 LogFileOperate 的对象,因为适配器本身就是 LogFileOperate 对象的子类;
以前调用被适配对象的方法的地方,全部修改成调用自己的方法。
类适配器和对象适配器的选择
从实现上:类适配器使用对象继承的方式,属于静态的定义方式。对象适配器使用对象组合的方式,属于动态组合的方式;
从工作模式上:类适配器直接继承了 Adaptee,使得适配器不能和 Adaptee 的子类一起工作。对象适配器允许一个 Adapter 和多个 Adaptee,包括 Adaptee 和它所有的子类一起工作;
从定义角度:类适配器可以重定义 Adaptee 的部分行为,相当于子类覆盖父类的部分实现方法。对象适配器要重定义 Adaptee 很困难;
从开发角度:类适配器仅仅引入了一个对象,并不需要额外的引用来间接得到 Adaptee。对象适配器需要额外的引用来间接得到 Adaptee。
总的来说,建议使用对象适配器方式。
- 设计模式的应用场景(7)--适配器模式
- Java设计模式之《适配器模式》及应用场景
- 设计模式应用场景
- 设计模式应用场景
- 设计模式应用场景
- 设计模式 应用场景
- 设计模式 应用场景
- 设计模式应用场景
- 设计模式应用场景
- 设计模式 应用场景
- 设计模式应用场景
- 各种设计模式的应用场景
- 常用设计模式的应用场景
- 常用设计模式的应用场景
- java设计模式的应用场景
- JAVA设计模式的应用场景
- Java设计模式的应用场景
- 一些常用设计模式的应用场景
- 数据库-mysql-linux下常用命令
- python tensorflow学习笔记(四)矩阵乘法
- Maven 项目打包,使用
- Java利用POI读取Excel表格
- 编译CxImage所遇到的问题汇总记录
- 设计模式的应用场景(7)--适配器模式
- 最近心情
- POJ 3261 Milk Patterns
- STL系列之四 heap 堆
- SpringMVC接收复杂集合参数
- 工作小结
- Java中的final关键字
- 大数据学习6:HDFS的一些理解
- 数组中出现次数超过一半的数字