设计模式第7式:适配器模式与外观模式

news2024/10/2 14:27:35

前言

前面讲的装饰者模式是将对象包装起来,并赋予新的职责。适配器模式同样是包装对象,但是目的不一样,它要让某些对象的接口看起来不像自己而是像别的东西。为什么要这样做,因为可以将类的接口转换成想要的接口。还会讲一个适配器的变种模式:外观模式,它将对象包装起来以简化其接口。

正文

1、现实世界的适配器模式

《Head First设计模式》给了一个很好的案例,就是我们如果想使用各国不同制式的插座,就需要一个电源适配器。在对象的世界里,适配器模式往往用于匹配旧系统和新需求之间的gap的。
在这里插入图片描述
将上面的图示解释成适配器模式就是下面这个图:

  1. 客户依据目标接口调用适配器的方法对适配器发出请求;
  2. 适配器使用被适配者的接口,将请求转换成被适配者的一个或多个接口;
  3. 客户收到返回的结果,但并未察觉这一切是适配器在起转换作用。

在这里插入图片描述

2、适配器模式定义

适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器模式可以让原本不兼容的类可以合作。

适配器模式有很好的OO设计原则:使用对象组合。现在来看它的类图:
在这里插入图片描述

3、适配器模式案例

旧世界的枚举器:Java早期的集合如Vector、Stack都实现了一个elements()方法,该方法返回一个Enumeration接口类型,这个接口可以逐一遍历集合的元素,而无需知道它们在集合内是如何被管理的。

public interface Enumeration<E> {
    boolean hasMoreElements();
    E nextElement();
}

新世界的迭代器:当Java推出新的集合后,开始应用Iterator迭代器(迭代器模式后面再讲)接口,这个接口和枚举接口很像,都可以遍历集合中的每个元素,只不过Iterator接口还提供了删除元素的能力。

public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove();
}

开发者作为客户,经常面对历史遗留代码,就像上面老容器的遍历。客户希望使用新的Iterator迭代器的接口规格来遍历老的集合。于是可以写一个适配器来适配新标准和老功能。我们来分析角色,开发者对应上图的Client,新标准接口Iterator就是Target,老功能Enumeration就是被适配者Adaptee。还缺一个重要角色:适配者Adapter。Java维护者或者开发者自己可以写一个适配器,这个适配器需要实现新标准接口Iterator,并组合老功能接口Enumeration。
在这里插入图片描述
实现代码如下:

public class EnumerationIterator implements Iterator {
    private Enumeration enumeration;

    public EnumerationIterator(Enumeration enumeration) {
        this.enumeration = enumeration;
    }

    @Override
    public boolean hasNext() {
        return enumeration.hasMoreElements();
    }

    @Override
    public Object next() {
        return enumeration.nextElement();
    }

    @Override
    public void remove() {
    	// 目标类不支持的动作无能为力
        throw new UnsupportedOperationException();
    }
}

4、适配器vs装饰器

两者都是组合对象,但是两个模式的目的不同,装饰器组合对象后在原有功能之上增强功能,适配器组合对象后编排原有功能使之能适配新接口标准。

5、外观模式

学习了前面后,我们知道适配器模式是将一个类的接口转换成另一个符合客户期望的接口。我们再来看一个改变接口的新模式,叫外观模式,它将一个或多个类的复杂实现都隐藏,只暴露一个干净的外观。可以将外观模式看做适配器模式的扩展。

外观模式提供了一个统一的接口,用来访问子系统的一群接口。

在这里插入图片描述

6、外观模式案例

家庭影院包含很多系统:DVD播放器、投影机、升降屏幕、音响等。每个系统都有自己的操作菜单,如果我们想要观赏一部电影,需要依次调用上面系统类的多个方法,非常复杂。于是我们创建一个家庭影院类,用它来包装各个子系统的复杂实现。代码其实很简单:

public class HomeTheaterFacade {
	// 组合各个子系统
	Amplifier amp;
	Tuner tuner;
	DvdPlayer player;
	...

	// 外观接口
	public void watchMovie() {
		// 编排接口
		amp.on();
		amp.setDvd(dvd);
		amp.setVolum(5);

		dvd.on();
		dvd.play(movie);
	}
}

7、最少知识原则

最少知识原则:只和你的密友谈话

这个原则希望我们再设计系统时,不要让太多的类耦合在一起,免得修改系统的一部分,会影响到其他部分。怎么避免呢?该原则给了一些方针:就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

  • 该对象本身;
  • 被当做方法参数而传递进来的对象;
  • 此方法内创建的对象;
  • 组合使用的对象;

举个例子,如果我们想从气象站获得当前温度,我们只需要知道气象站对象就够了,不需要再认识气象站本身依赖的其他对象。

// 不采用此原则
getTemp() {
	// 这里我们从气象站获得了温度计对象Thermometer,再获得温度
	Thermometer ther = station.getThermometer();
	return ther.getTemperture();
}
// 采用此原则
getTemp() {
	// 应用此原则后,在气象站中加一个获取温度方法,减少类的依赖
	return  station.getTemperture();
}

总结

适配器模式组合对象,改变老功能行为以适配新的接口标准;
外观模式组合对象,提供简洁的外观接口,隐藏复杂的子系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/337872.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++中的枚举与位域

枚举在传统 C中&#xff0c;枚举类型并非类型安全&#xff0c;枚举类型会被视作整数&#xff0c;则会让两种完全不同的枚举类型可以进行直接的比较&#xff08;虽然编译器给出了检查&#xff0c;但并非所有&#xff09;&#xff0c;甚至同一个命名空间中的不同枚举类型的枚举值…

GPR后期功能整理

基金本子写得太困难了&#xff0c;学术水平不够&#xff0c;好的想法未想到好的科学问题&#xff0c;难以下笔。和龙工沟通后&#xff0c;得到了大量impulse radar的数据&#xff0c;后期需要进行分析&#xff0c;从而能让GPR智能识别走得更远。从数据解译角度&#xff0c;找到…

配置CMAKE编译环境:VSCODE + MinGW

一. MinGW安装 MinGW(Minimalist GNU For Windows)是个精简的Windows平台C/C、ADA及Fortran编译器&#xff0c;相比Cygwin而言&#xff0c;体积要小很多&#xff0c;使用较为方便。 MinGW最大的特点就是编译出来的可执行文件能够独立在Windows上运行。 MinGW的组成&#xff…

[Linux]进程替换

&#x1f941;作者&#xff1a; 华丞臧. &#x1f4d5;​​​​专栏&#xff1a;【LINUX】 各位读者老爷如果觉得博主写的不错&#xff0c;请诸位多多支持(点赞收藏关注)。如果有错误的地方&#xff0c;欢迎在评论区指出。 推荐一款刷题网站 &#x1f449; LeetCode刷题网站 文…

HashMap设计思想学习

HashMap设计思想学习引言树化与退化红黑树的优势索引计算put流程扩容&#xff08;加载&#xff09;因子为何默认是 0.75fhashMap并发丢失数据问题jdk 1.7并发死链问题key 的设计引言 hashmap在jdk 1.7之前是数组链表结构&#xff0c;而jdk1.8之后变为是数组(链表|红黑树) 树化…

【第38天】不同路径数问题 | 网格 dp 入门

本文已收录于专栏&#x1f338;《Java入门一百例》&#x1f338;学习指引序、专栏前言一、网格模型二、【例题1】1、题目描述2、解题思路3、模板代码4、代码解析5.原题链接三、【例题2】1、题目描述2、解题思路3、模板代码4、代码解析5.原题链接三、推荐专栏四、课后习题序、专…

大型物流运输管理系统源码 TMS源码

大型物流运输管理系统源码 TMS是一套适用于物流公司的物流运输管理系统&#xff0c;涵盖物流公司内部从订单->提货->运单->配车->点到->预约->签收->回单->代收货款的全链条管理系统。 菜单功能 一、运营管理 1、订单管理&#xff1a;用于客户意向订…

ChatGPT 到底强大在哪里?(文末有彩蛋)

ChatGPT 是由 OpenAI 开发的一个人工智能聊天机器人程序&#xff0c;于2022年11月推出。该程序使用基于 GPT-3.5 架构的大型语言模型并通过强化学习进行训练。ChatGPT 以文字方式交互&#xff0c;而除了可以通过人类自然对话方式进行交互&#xff0c;还可以用于相对复杂的语言工…

一定要收藏的面试思维导图,粉丝分享面试经验

一位粉丝分享面试经验&#xff1a;1.常见面试题有哪些&#xff1f;主要从以下一些知识点做了准备&#xff1a; 常用的分析方法、Excel、SQL、 A/B测试、产品分析。然后每份面试针对职位要求&#xff0c;还有前期和HR聊天一点点了解这个职位之后&#xff0c;定向准备。 Excel、S…

OpenMMLab 实战营打卡 - 第 7 课

OpenMMLab MMSegmentation内容概要MMSegmentation统一超参MMSegmentation 的项目结构分割模型的模块化设计分割模型的配置文件主干网络的配置ResNet v1c主解码头的配置辅助解码头的配置数据集配置数据处理流水线常用训练策略参考资料内容概要 • MMSegmentation 项目概述 • M…

TSDF算法应用与源码详解

数据与代码链接见文末 1.TSDF整体概述 (1)需要准备的输入 1.原始图片;2.对应的深度信息;3.每张图的相机位姿;4.相机内参 原始输入图像数据(就是一个场景多个视角拍摄的结果) 输入图像的深度信息,位姿信息等(一般由相机得到,也可以通过算法得到) (2)整体概述…

【DFS并查集】岛屿数量

经典的dfs/bfs问题&#xff0c;给一个起点开始搜索&#xff0c;满足条件则继续调用dfs/bfs 从没有访问过的某个陆地出发&#xff0c;将所有能到达的陆地的状态都记录为已访问。下次出发不从已访问的陆地出发&#xff0c;每次出发前都把岛屿数 1即可 class Solution { public…

STM32开发(9)----CubeMX配置外部中断

CubeMX配置外部中断前言一、什么是中断1.STM32中断架构体系2.外部中断/事件控制器&#xff08;EXTI&#xff09;3.嵌套向量中断控制器&#xff08;NIVC&#xff09;二、实验过程1.CubeMX配置2.代码实现3.硬件连接4.实验结果总结前言 本章介绍使用STM32CubeMX对引脚的外部中断进…

MySQL 3:MySQL数据库基本操作 DQL

数据库管理系统的一个重要功能是数据查询。数据查询不应简单地返回数据库中存储的数据&#xff0c;还应根据需要对数据进行过滤&#xff0c;确定数据的显示格式。MySQL 提供了强大而灵活的语句来实现这些操作。MySQL数据库使用select语句查询数据。 select [all|distinct]<…

09- 机器学习经典流程 (中国人寿保费项目) (机器学习)

删除特征: data data.drop([region, sex], axis1)特征数据调整: data.apply( ) # 体重指数&#xff0c;离散化转换&#xff0c;体重两种情况&#xff1a;标准、肥胖 def convert(df,bmi):df[bmi] fat if df[bmi] > bmi else standardreturn df data data.apply(convert, …

EXCEL-职业版本(1)

EXCEL职业版本(1) 工作表 插入 注&#xff1a;默认会在鼠标选中的sheet后面新增&#xff0c;例如图中&#xff0c;当前选中的是sheet2&#xff0c;点击新增后会在sheet2后面自动新增一个sheet 删除 移动或者复制 类似于copy一整个sheet的所有内容 step1 右击【sheet名称】选…

Cordova

一、简介 Cordova 是用 Web 技术&#xff08; HTML&#xff0c;CSS 和 JS &#xff09;构建移动应用的平台。我们可以认为Cordova 是一个容器&#xff0c;用于将的 Web 应用移植到移动端&#xff0c;同时支持移动端的功能&#xff08;例如&#xff1a;定位、蓝牙、摄像头等&am…

Linux内核并发与竞争-原子操作

一.原子操作的概念首先看一下原子操作&#xff0c;原子操作就是指不能再进一步分割的操作&#xff0c;一般原子操作用于变量或者位操作。假如现在要对无符号整形变量 a 赋值&#xff0c;值为 3&#xff0c;对于 C 语言来讲很简单&#xff0c;直接就是&#xff1a; a3但是 C 语言…

机器学习基本原理总结

本文大部分内容参考《深度学习》书籍&#xff0c;从中抽取重要的知识点&#xff0c;并对部分概念和原理加以自己的总结&#xff0c;适合当作原书的补充资料阅读&#xff0c;也可当作快速阅览机器学习原理基础知识的参考资料。 前言 深度学习是机器学习的一个特定分支。我们要想…

Elasticsearch bucket_script、bucket_selector、bucket_sort 区别和应用场景?

1、实战问题POST test-002/_bulk {"index":{"_id":1}} {"name": "张三","city": "beijing"} {"index":{"_id":2}} {"name": "李四","city": "beijing&qu…