【结构型模式】适配器模式

news2024/11/18 9:00:51

一、适配器模式概述

        适配器模式的定义-意图将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。(对象结构模式->对象适配器/类结构模式->类适配器)

        适配器模式包含三个角色:目标(Target)角色、适配者(Adaptee)角色和适配器(Adapter)角色。根据Adapter角色的实现不同,可分为类适配器和对象适配器

  • 类适配器模式(继承也是泛化实现):适配器角色对于被适配角色的适配是通过继承完成的还是通过组合来完成的。通过继承类适配者类(Adaptee Class)实现的,另外类适配器实现客户类所需要的接口。当客户对象调用适配器类方法的时候,适配器内部调用它所继承的适配者的方法。

  •  对象适配器模式(组合实现):适配器角色对于被适配角色的适配是通过组合来完成的。包含一个适配器者的引用(reference),与类适配器相同,对象适配器也实现了对客户类需要用接口。当客户对象调用对象适配器的方法的时候,对象适配器调它所包含的适配器者实例的适当方法。

  • 适配器模式的优缺点
    • 优点
      • 1.将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构;
      • 2.增加了类的透明性和复用性,提高了适配者的复用性,同一个适配者类可以在多个不同的体统中复用;
      • 3.灵活性和扩展性非常好;
      • 4.类适配器模式:置换一些适配者的发放很方便;
      • 5.对象适配器模式:可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类。
    • 缺点
      • 1.类适配器模式:
        • ①一次最多只能适配一个适配者类,不能同时适配多个适配者;
        • ②适配者类不能为最终类(不能为final);
        • ③目标抽象类只能为接口,不能为类。
      • 2.对象适配器模式:在适配器中置换适配者类的某些方法比较麻烦。
  • 适用环境
    • 1.系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码;
    • 2.创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作。

二、缺省适配器

       缺省适配器模式(Defualt Adapter Pattern)的定义当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为借口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又成为单接口适配器模式

        结构

  • 适配者接口(ServiceInterface)
  • 缺省适配器类(AbstractServiceClass)
  • 具体业务类(ConcreteServiceClass)。

三、双向适配器

        双向适配器定义在对象适配器的使用过程,如果在适配器中同时包含对目标类和适配者类的引用,适配者可以通过对它调用目标类中的方法,目标类也可以通过它调用适配者类中的方法,那么该适配器就是一个双向适配器。

        结构

  • 目标(Target)角色
  • 适配者(Adaptee)角色
  • 适配器(Adapter)角色。

四、代码实现

        适配器模式的结构和实现:

  • 1.目标(Target)角色:这是客户所期待的接口。因为Java不支持多继承,所以Target必须是接口,不可以是类。
  • 2.适配者(Adaptee)角色:需要适配的类。
  • 3.适配器(Adapter)角色:把源接口转换成目标接口。
        4.1 对象适配器

        某公司欲开发一款儿童玩具汽车,为了更好地吸引小朋友的注意力,该玩具汽车在移动过程中伴随着灯光闪烁和声音提示。在该公司以往的产品中已经实现了控制灯光闪烁(例如警灯闪烁)和声音提示(例如警笛音效)的程序,为了重用先前的代码并且使得汽车控制软件具有更好的灵活性和扩展性,现使用适配器模式设计该玩具汽车控制软件。

        4.1.1 目标(Target)角色(CarController:汽车控制类,充当目标抽象类)
package Adapter.car;
//汽车控制类,充当目标抽象类
public abstract class CarController {
	public void move() {
		System.out.println("车开始移动!");
	}
	public abstract void phonate();//发出声音
	public abstract void twinkle();//灯光闪烁
}
        4.1.2 适配者(Adaptee)角色(PoliceSound:警笛类,充当适配者;PoliceLamp:警灯类,充当适配者)
package Adapter.car;
//警车声音类,充当适配器
public class PoliceSound {
	public void alarmSound() {
		System.out.println("发出警车声音!");
	}
}
package Adapter.car;
//警车灯类,充当适配者
public class PoliceLamp {
	public void alarmLamp() {
		System.out.println("呈现警车灯闪烁!");
	}
}
        4.2.3 适配器(Adapter)角色(PoliceCarAdapter:警车适配器,充当适配器)
package Adapter.car;
//适配器角色
public class PoliceCarAdapter extends CarController{
	//定义适配者PoliceSound对象
	private PoliceSound sound;
	//定义适配者PoliceLamp对象
	private PoliceLamp lamp;
	public PoliceCarAdapter() {
		sound=new PoliceSound();
		lamp=new PoliceLamp();
	}
	@Override
	public void phonate() {
		// TODO 自动生成的方法存根
		sound.alarmSound();
	}

	@Override
	public void twinkle() {
		// TODO 自动生成的方法存根
		lamp.alarmLamp();
	}

}
        4.2.4 main方法实现对象适配器模式
package Adapter.car;

public class Test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		CarController cc;//针对抽象目标编程
		//cc =new AmbulanceCarAdapter();//救护车适配器
		//cc.move();
		//cc.twinkle();
		//cc.phonate();
		System.out.println("----------------");
		cc=new PoliceCarAdapter();//警车适配器
		cc.move();
		cc.twinkle();
		cc.phonate();	
	}
}
        4.1.5 UML图

        4.2 缺省适配器

        本科生毕业条件:1.本科生必须读完读四年修满所有的学分后,参加论文答辩后即可毕业;2.学校采用的弹性学分制,只要修满所有的学分,可以提前安排答辩早毕业。

        要求:分别实现以下三种情况的学生类,并编写测试类运行。

  • 1)普通的就读四年的全日制大学生 GeneralStudent
  • 2)读了3年提前修满学分特殊的大学生SpecialStudent
  • 3)读到大二就退学的大学生DiscontinueStudyStudent
        4.2.1 目标(Target)角色(Study:学分接口,充当目标接口)

 

package Adapter.defualtAdapter.Student;
//目标Target角色
public interface Study {
	//四个学期和论文答辩
	public void StudyGrade1();
	public void StudyGrade2();
	public void StudyGrade3();
	public void StudyGrade4();
	public void TheisPresentation();
}
        4.2.2 适配者(Adaptee)角色(GeneralStudent、SpecialStudent、DiscountinueStudyStudent:充当适配者)

 

package Adapter.defualtAdapter.Student;
//Adaptee普通全日制大学生
public class GeneralStudent extends StudyAdapter{
	public GeneralStudent(String name) {
		super(name);
	}
	public void StudyGrade1(){
		System.out.println("读完大学一年级");
	}
	public void StudyGrade2(){
		System.out.println("读完大学二年级");
	}
	public void StudyGrade3(){
		System.out.println("读完大学三年级");
	}
	public void StudyGrade4(){
		System.out.println("读完大学四年级");
	}
	public void TheisPresentation() {
		super.TheisPresentation();
		System.out.println("修满了学分,参加论文答辩,成功毕业!");
	}
}
package Adapter.defualtAdapter.Student;
//Adaptee跳级的大学生
public class SpecialStudent extends StudyAdapter{
	public SpecialStudent(String name) {
		super(name);
	}
	public void StudyGrade1(){
		System.out.println("读完大学一年级");
	}
	public void StudyGrade2(){
		System.out.println("读完大学二年级");
	}
	public void TheisPresentation() {
		super.TheisPresentation();
		System.out.println("修满了学分,参加论文答辩,成功毕业!");
	}
}
package Adapter.defualtAdapter.Student;
//Adaptee辍学的大学生
public class DiscountinueStudyStudent extends StudyAdapter{

	public DiscountinueStudyStudent(String name) {
		super(name);
	}
	public void StudyGrade1(){
		System.out.println("读完大学一年级");
	}
	public void TheisPresentation() {
		super.TheisPresentation();
		System.out.println("中途辍学!");
	}
}
        4.2.3 适配器(Adapter)角色(StudyAdapter:学分适配器,充当适配器)
package Adapter.defualtAdapter.Student;
//适配器Adapter
public abstract class StudyAdapter implements Study{
	String name;
	public StudyAdapter(String name) {
		this.name=name;
	}
	public void StudyGrade1(){}
	public void StudyGrade2(){}
	public void StudyGrade3(){}
	public void StudyGrade4(){}
	public void TheisPresentation() {
		System.out.println("我是"+name);
		StudyGrade1();
		StudyGrade2();
		StudyGrade3();
		StudyGrade4();
	}
}
        4.2.4 main方法实现缺省适配器模式
package Adapter.defualtAdapter.Student;

public class Test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		StudyAdapter s= new GeneralStudent("Emily");;//针对抽象目标接口编程
		s.TheisPresentation();
		System.out.println("-----------------------");
		StudyAdapter s1= new SpecialStudent("zz");;//针对抽象目标接口编程
		s1.TheisPresentation();
		System.out.println("-----------------------");
		StudyAdapter s2= new DiscountinueStudyStudent("xx");;//针对抽象目标接口编程
		s2.TheisPresentation();
	}

}
        4.2.5 UML图

        4.3 双向适配器
  • 1.灰太狼临死前他将自己的抓羊秘技传给了已经成年的小灰灰,并留下一件狼皮和一件羊皮。小灰灰也承担起了抓羊的重任;
  • 2.小灰灰和羊相爱了,但是在梁山上,狼只能一直披着羊皮生活;
  • 3.小灰灰带媳妇回去看妈妈。

        他们改造成了一个新型的法宝——狼羊双向适配器。把羊皮和狼皮缝在一起,正面羊皮,翻过来后就是狼皮,这样一件衣服,既能扮狼又能扮羊。

        4.3.1 目标(Target)角色(ISheep、IWolf:充当目标接口)
package Adapter.doubleAdapter.wolfsheep;
//目标角色
public interface ISheep {
	public void sheepLooks();
	public void eatGrass();
}
package Adapter.doubleAdapter.wolfsheep;
//目标角色
public interface IWolf {
	public void wolfLooks();
	public void eatMeat();
}
        4.3.2 适配者(Adaptee)角色(Sheep、Wolf:充当适配者)
package Adapter.doubleAdapter.wolfsheep;
//适配者
public class Sheep implements ISheep {

	@Override
	public void sheepLooks() {
		System.out.println("I am a sheep,too!");
	}

	@Override
	public void eatGrass() {
		System.out.println("I eat grass!");
	}

}
package Adapter.doubleAdapter.wolfsheep;
//适配者
public class Wolf implements IWolf {

	@Override
	public void wolfLooks() {
		System.out.println("I am a wolf,too!");
	}

	@Override
	public void eatMeat() {
		System.out.println("I eat meat!");
	}

}
        4.3.3 适配器(Adapter)角色(TwoFaceAdapter:充当适配器)
package Adapter.doubleAdapter.wolfsheep;
//适配器
public class TwoFaceAdapter implements ISheep, IWolf {
	ISheep sheep =null;
	IWolf wolf =null;
	public TwoFaceAdapter(ISheep sheep) {
		this.sheep=sheep;
	}
	public TwoFaceAdapter(IWolf wolf) {
		this.wolf=wolf;
	}
	@Override
	public void wolfLooks() {
		System.out.println("I am a wolf,too!");
	}

	@Override
	public void eatMeat() {
		// TODO 自动生成的方法存根		
		sheep.eatGrass();
	}

	@Override
	public void sheepLooks() {
		// TODO 自动生成的方法存根
		System.out.println("I am a sheep,too!");
	}

	@Override
	public void eatGrass() {
		// TODO 自动生成的方法存根
		wolf.eatMeat();
	}

}
        4.3.4 main方法实现双向适配器模式
package Adapter.doubleAdapter.wolfsheep;

public class Test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		//把羊设配成狼
		ISheep fakersheep = new TwoFaceAdapter(new Wolf());
		fakersheep.sheepLooks();
		fakersheep.eatGrass();
		//把狼设配成羊
		IWolf fakerwolf = new TwoFaceAdapter(new Sheep());
		fakerwolf.wolfLooks();
		fakerwolf.eatMeat();
	}

}
        4.3.5 UML图

五、代码结构图

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

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

相关文章

又成长了,异常掉电踩到了MySQL主从同步的坑!

📢📢📢📣📣📣 哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】!😜&am…

VUE 使用 Vite 创建一个 vue3.0 + vite 项目

Vite 是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成: 1. 一个开发服务器,它基于 原生 ES 模块 提供了 丰富的内建功能,如速度快到惊人的 模块热更新(HMR)。 2. 一套构建指令&#…

yolov5-6.0调测记录

直接运行yolov5-6.0/detect.py,输出如下: image 1/2 C:\Users\dun\Downloads\yolov5-6.0\data\images\bus.jpg: 640x480 4 persons, 1 bus, Done. (0.216s) image 2/2 C:\Users\dun\Downloads\yolov5-6.0\data\images\zidane.jpg: 384x640 2 persons, 2…

Java+springboot开发的医院智能导诊服务系统源码 自动兼容小程序与H5版本

智能导诊系统 一、什么是智慧导诊系统? 智慧导诊系统是一种医院使用的引导患者自助就诊挂号、精准推荐科室、引导患者挂号就诊的系统。该系统结合医院挂号及就诊的HIS系统,为患者带来全流程的信息指引提醒,可以在全院区构建一个精细化、移动…

css层叠性,继承性,优先级

前言 本文概要:讲述css的三大特性,层叠,继承和优先级。 层叠性 描述:我们试想以下这种情况:我们定义了同一个选择器,但是定义的属性不同。属性有相同的也有不同的,那么最后我们这个页面会听谁的…

Liunx入门学习 之 基础操作指令讲解(小白必看)

股票的规律找到了,不是涨就是跌 一、Linux下基本指令 1.ls 指令 2.pwd 命令 3.cd 指令 4.touch 指令 5.mkdir 指令 6.rmdir指令 && rm 指令 7.man 指令 8.cp 指令 9.mv指令 10.cat 11.more 指令 12.less 指令 13.head 指令 14.tail 指令 15…

轮腿机器人-五连杆正运动学解算

轮腿机器人-五连杆与VMC 1.五连杆正运动学分析2.参考文献 1.五连杆正运动学分析 如图所示为五连杆结构图,其中A,E为机器人腿部控制的两个电机,θ1,θ4可以通过电机的编码器测得。五连杆控制任务主要关注机构末端C点位置,其位置用直…

解读UUID:结构、原理以及生成机制

在计算机科学领域,UUID(Universally Unique Identifier)是一种用于唯一标识信息的标准。UUID的生成机制和结构设计使其在分布式系统和数据库中广泛应用。本文将深度解读UUID的结构、原理以及生成机制,帮助读者更好地理解这一重要概…

【北京迅为】《iTOP-3588开发板系统编程手册》-第14章 GPIO应用编程

RK3588是一款低功耗、高性能的处理器,适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用,RK3588支持8K视频编解码,内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

Vue3: toRefs与toRef的基本使用

一、前言 本文主要介绍toRefs与toRef的基本使用。 二、内容 1、基本概念 作用: toRefs与toRef可以将一个响应式对象中的每一 个属性,转换为ref对象;不同 toRefs与toRef功能一致,但toRefs可以批量转换。 2、toRefs 如果把reactive定义的…

论文解读-ASAP: Fast Mobile Application Switch via Adaptive Prepaging

研究背景: 用户使用移动设备同时打开多个App,很容易造成移动设备的内存紧缺。现有解决方法一般采用杀死守护进程(lmkd)来释放内存或者基于压缩算法的in-memory swap(ZRAM)方式, 这些方法会面临用户切换回被杀死的进程过…

构建有序链表,有序链表的归并,反转链表

本次将对于构建有序链表,有序链表的归并,反转链表,进行一一介绍和代码分享。 首先是一些链表中的基本的函数: Node* creatList() {Node* headNode (Node*)malloc(sizeof(Node));assert(headNode);headNode->next NULL;retu…

汽车摄像头匿名化处理解决方案,保护信息的安全性和隐私性

随着智能交通和自动驾驶技术的迅猛发展,汽车摄像头已成为现代汽车不可或缺的一部分,摄像头所捕捉的图像信息也引发了日益严峻的信息安全问题。如何在充分利用摄像头功能的同时,保障个人隐私和信息安全,已成为企业亟待解决的问题。…

CPRI协议理解——帧格式中的计数标识

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 CPRI协议理解——帧格式中的计数标识 前言帧格式中的计数标识总结 前言 CPRI协议是一个流式协议,数据不间断的传输,在我们要了解CPRI到底要传输种类繁…

HDMI to TYPE-C芯片|HDMI2.0转TYPE-C转接器方案|CS5802设计方案|ASL CS5802

CS5802输入端可以是1080P、4K30、4K60HZ这三种规格,输出的接口可以是TYPE-C信号接口,或者是TYPE-C信号接口,输入端HDMI由4路信号组成,支持1.62Gbps、2.7Gbps、5.4Gbps链路速率。内置可选SSC功能可降低EMI的干扰状况。 ASL CS5802芯片概述: 符合HDMI规范…

抖去推短视频矩阵系统----源头开发

为什么一直说让企业去做短视频矩阵?而好处就是有更多的流量入口,不同平台或账号之间可以进行资源互换,最终目的就是获客留咨,提单转化。你去看一些做得大的账号,你会发现他们在许多大的平台上,都有自己的账…

基于Python利用zhconv模块进行简繁体字转换

在处理中文文本时,简繁体字之间的转换是一项常见的任务。Python提供了许多库来实现这个目的,其中之一就是zhconv。zhconv是一个Python库,提供了简体字和繁体字之间的转换功能。本教程将向你展示如何使用zhconv模块来实现简繁体字的互转&#…

【MATLAB】App 设计 (入门)

设计APP 主界面 函数方法 定时器 classdef MemoryMonitorAppExample < matlab.apps.AppBase% Properties that correspond to app componentsproperties (Access public)UIFigure matlab.ui.FigureStopButton matlab.ui.control.ButtonStartButton matlab.ui.cont…

用户行为分析模型实践(四)—— 留存分析模型

作者&#xff1a;vivo 互联网大数据团队- Wu Yonggang、Li Xiong 本文是vivo互联网大数据团队《用户行为分析模型实践》系列文章第4篇 -留存分析模型。 本文详细介绍了留存分析模型的概念及基本原理&#xff0c;并阐述了其在产品中具体实现。针对在实际使用过程问题&#xff0…

力扣---从前序与中序遍历序列构造二叉树

给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]示…