设计模式06-结构型模式1(适配器/桥接/组合模式/Java)

ops/2024/10/30 10:52:04/

#1024程序员节|征文#在这里插入图片描述

4.1 适配器模式

  • 结构型模式(Structural Pattern)的主要目的就是将不同的类和对象组合在一起,形成更大或者更复杂的结构体。
  • 结构性模式的分类:

类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关。

对象结构型模式关心类与对象的组合,通过关联关系在一个类中定义另一个类的实例对象,然后通过该对象调用相应的方法。根据合成复用原则,在系统中尽量使用关联关系替代继承关系,因此大部分结构型模式都是对象结构型模式

4.1.1 适配器模式的定义

1.动机:适配器可以使由于接口不兼容而不能交互的类可以一起工作,这就是适配器模式的模式动机。

2.定义:将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器

4.1.2 适配器模式的分析与实现

在适配器模式中可以定义一个包装类,包装不兼容接口的对象,这个包装类指的就是适配器(Adaptor),它所包装的对象就是适配者(Adaptee),即被适配的类。适配器提供客户类需要的接口适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说,当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类

类适配器:

image-20241025213034577

java">public interface Target {public void request();
}
public class Adaptee {public void specialRequest() {System.out.println("特殊的请求方式");}
}
public class Adapter extends Adaptee implements Target{@Overridepublic void request() {super.specialRequest();}
}

对象适配器:

image-20241025213054460

java">public interface Target {public void request();
}
public class Adaptee {public void specialRequest() {System.out.println("特殊的请求方式");}
}
public class Adapter implements Target {private Adaptee adaptee;public void setAdaptee(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specialRequest();}
}
  • 类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之不可用。

  • 适配者类无法继承时,只能用对象适配器。

4.1.3 适配器模式的案例

现需要设计一个可以模拟各种动物行为的机器人,在机器人中定义了一系列方法,如机器人叫喊方法cry()、机器人移动方法move()等。如果希望在不修改已有代码的基础上使得机器人能够像狗一样叫,像狗一样跑,使用适配器模式进行系统设计。

image-20241025214944924

java">public interface Robot {public void cry();public void move();
}
public class Dog {public void cry() {System.out.println("汪汪叫");}public void move() {System.out.println("快快跑");}
}
public class DogAdapter extends Dog implements Robot{public void cry(){super.cry();}public void move(){super.move();}
}
4.1.4 适配器模式的优缺点
优点缺点
1.将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构
2.增加了类的透明性和复用性,提高了适配者的复用性
3.灵活性和扩展性非常好,更换(增加)适配器,符合开闭原则
4.类适配器模式:由于继承关系,置换一些适配者的方法很方便不能适配多个适配类,每个目标类必须为接口,对于适配类为finial修饰的不可使用
5.对象适配器模式:可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类在适配器中置换适配者类的某些方法比较麻烦
4.1.5 适配器模式的适用场景
  • 系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码

  • 创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作

4.1.6 双向适配器类

image-20241025215726923

java">public class Adapter implements Target,Adaptee {private Target target;private Adaptee adaptee;public Adapter(Target target) {this.target = target;    }	public Adapter(Adaptee adaptee) {this.adaptee = adaptee;    }	public void request() {adaptee.specificRequest();    }	public void specificRequest() {target.request();    }
}

4.2 桥接模式

4.2.1 桥接模式的定义

1.动机:如果系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使得两者可以独立扩展。桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联取代了传统的多重继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效地控制了系统中类的个数。

2.定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

4.2.2 桥接模式的分析与实现

image-20241026112712436

  • 桥接模式中体现开闭原则、合成复用原则、里氏代换原则、依赖倒转原则等。

  • 脱耦:桥接模式将抽象化和实现化之间的耦合解开,或者说是将强关联(继承)改换成弱关联,将两个角色之间的继承关系改为关联关系,使得两者可以独立变化。

    java">public interface Implementor {public void implOperation();
    }
    public class ConcreteImplementorA implements Implementor{@Overridepublic void implOperation() {System.out.println("一个实体的维度1的特征A");}
    }
    public class ConcreteImplementorB implements Implementor{@Overridepublic void implOperation() {System.out.println("一个实体的维度1的特征B");}
    }public abstract class Abstracter {protected Implementor implementor;public void setImplementor(Implementor implementor) {this.implementor = implementor;}public abstract void operation();
    }
    public class RefinedAbstracter extends Abstracter{@Overridepublic void operation() {System.out.println("一个实体维度2的特征");implementor.implOperation();}
    }
    
4.2.3 桥接模式的案例

image-20241026114242202

image-20241026114302188

java">public interface VideoFile {public void decode(String osType, String fileName);
}
public class MPEGFile implements VideoFile{@Overridepublic void decode(String osType, String fileName) {System.out.println("位于" + osType + "操作系统的" + fileName + ".MPEG文件进行播放");}
}
public class WMVFile implements VideoFile{@Overridepublic void decode(String osType, String fileName) {System.out.println("位于" + osType + "操作系统的" + fileName + ".WMV文件进行播放");}
}
java">public abstract class OSVersion {protected VideoFile videoFile;public void setVideoFile(VideoFile videoFile) {this.videoFile = videoFile;}public abstract void play(String fileName);
}
public class LinuxVersion extends OSVersion{@Overridepublic void play(String fileName) {videoFile.decode("Linux", fileName);}
}
public class WindowsVersion extends OSVersion{@Overridepublic void play(String fileName) {videoFile.decode("Windows", fileName);}
}
java">public class Main {public static void main(String[] args) {WMVFile wmvFile = new WMVFile();WindowsVersion windowsVersion = new WindowsVersion();windowsVersion.setVideoFile(wmvFile);windowsVersion.play("刺客五六七");MPEGFile mpegFile = new MPEGFile();LinuxVersion linuxVersion = new LinuxVersion();linuxVersion.setVideoFile(mpegFile);linuxVersion.play("喜羊羊与灰太狼");}
}
4.2.4 桥接模式的优缺点
优点缺点
1.分离抽象接口和实现部分1.不容易正确识别俩个变化的维度
2.取代多继承,减少子类个数2.关联关系在抽象层,设计难度大
3.扩展性,俩个维度均可扩展
4.2.5 桥接模式的适用场景
  • 需要在抽象化和具体化之间增加更多的灵活性,扩展性,避免在两个层次之间建立静态的继承关系

  • 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立地进行扩展

  • 不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统

4.3 组合模式

4.3.1 组合模式的定义

1.动机:描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器对象和叶子对象。

2.定义:组合多个对象形成树形结构以表示“部分-整体”的结构层次。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性。

4.3.2 组合模式的分析与实现
image-20241026175600054
  • 组合模式用面向对象的方式来处理树形结构,它为叶子构件和容器构件提供了一个公共的抽象构件类,客户端可以针对该抽象类进行处理,而无需关心所操作的是哪种类型的对象。
  • 使用聚合关系使得容器既可以添加叶子节点也可以添加容器
java">public abstract class Component {public abstract void add(Component component);public abstract void remove(Component component);public abstract Component getChild(int i);public abstract void method();
}public class Composite extends Component{private ArrayList<Component> list = new ArrayList<>();@Overridepublic void add(Component component) {list.add(component);}@Overridepublic void remove(Component component) {list.remove(component);}@Overridepublic Component getChild(int i) {return list.get(i);}@Overridepublic void method() {for (Component component : list) {component.method();}}
}public class Leaf extends Component{@Overridepublic void add(Component component) {throw new RuntimeException("叶子节点无法添加元素");}@Overridepublic void remove(Component component) {throw new RuntimeException("叶子节点无法删除元素");}@Overridepublic Component getChild(int i) {throw new RuntimeException("叶子节点无法获取元素");}@Overridepublic void method() {}
}
4.3.3 组合模式的案例

在操作系统中,一个文件夹中可能存放着图像文件,视频文件,文本文件,也可能存放其他的文件夹,而对不同类型的文件进行的浏览操作也不一样。

image-20241026181555090
java">public abstract class AbstractFile {protected String fileName;public abstract void display();public abstract void add(AbstractFile file);public abstract void remove(AbstractFile file);
}
java">public class ImageFile extends AbstractFile{public ImageFile(String fileName) {this.fileName = fileName;}@Overridepublic void display() {System.out.println("正在打开" + this.fileName + ".png");}@Overridepublic void add(AbstractFile file) {throw new RuntimeException("无法添加文件");}@Overridepublic void remove(AbstractFile file) {throw new RuntimeException("无法删除文件");}
}
public class TextFile extends AbstractFile{public TextFile(String fileName) {this.fileName = fileName;}@Overridepublic void display() {System.out.println("正在打开" + this.fileName + ".txt");}@Overridepublic void add(AbstractFile file) {throw new RuntimeException("无法添加文件");}@Overridepublic void remove(AbstractFile file) {throw new RuntimeException("无法删除文件");}
}
java">public class Folder extends AbstractFile{private ArrayList<AbstractFile> files;public Folder(String fileName) {files = new ArrayList<>();this.fileName = fileName;}@Overridepublic void display() {System.out.println("打开" + this.fileName + "文件夹");for (AbstractFile file : files) {file.display();}}@Overridepublic void add(AbstractFile file) {this.files.add(file);}@Overridepublic void remove(AbstractFile file) {this.files.remove(file);}
}
4.3.4 组合模式的优缺点
优点缺点
1.可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次1.在增加新构件时很难对容器中的构件类型进行限制
2.客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构2.不是所有方法在叶子节点中都可以使用
3.增加新的容器构件和叶子构件都很方便,符合开闭原则
4.3.5 组合模式的适用场景
  • 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们

  • 在一个使用面向对象语言开发的系统中需要处理一个树形结构

  • 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型

4.3.6 组合模式的类型

image-20241026182814601

定义:抽象构件中声明了所有用于管理成员对象的方法,包括add()、remove(),以及getChild()等方法。

优点:确保所有的构件类都有相同的接口,客户端一致对待所有对象。

缺点:不够安全,因为叶子对象和容器对象在本质上是有区别的。

image-20241026182755661

定义:抽象构件Component中没有声明任何用于管理成员对象的方法,在Composite类中声明与实现这些方法

优点:优点是安全,对于叶子对象,客户端不可能调用到这些方法

缺点:不够透明,客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件


http://www.ppmy.cn/ops/129556.html

相关文章

C语言中的位操作

第一章 变量某位赋值与连续赋值 寄存器 | 值 //例如&#xff1a;a 1000 0011b a | (1<<2) //a 1000 0111 b 单独赋值 a | (3<<2*2) // 1011 0011b 连续赋值 第二章 变量某位清零与连续清零 寄存器 & ~&#xff08;&#xff09; 值 //例子&#xff1a;a …

MATLAB车道检测与跟踪

读了车道检测这个论文&#xff0c;我理解了利用matlab对车道识别算法进行仿真研究&#xff0c;从仿真的结果中提出具有一定实时性鲁棒性的识别方法。车道检测是智能车辆发展的智能因素。近年来对这项目的研究都是针对特定的环境和道路状况给出了不同的解决方案。近年来,自主驾驶…

NVR小程序接入平台/设备EasyNVR多个NVR同时管理视频监控新选择

在数字化转型的浪潮中&#xff0c;视频监控作为安防领域的核心组成部分&#xff0c;正经历着前所未有的技术革新。随着技术的不断进步和应用场景的不断拓展&#xff0c;视频监控系统的兼容性、稳定性以及安全性成为了用户关注的焦点。NVR小程序接入平台/设备EasyNVR&#xff0c…

【本科毕业设计】基于单片机的智能家居防火防盗报警系统

基于单片机的智能家居防火防盗报警系统 源码下载摘要Abstract第1章 绪论1.1课题的背景1.2 研究的目的和意义 第2章 系统总体方案设计2.1 设计要求2.2 方案选择和论证2.2.1 单片机的选择2.2.2 显示方案的选择 第3章 系统硬件设计3.1 整体方案设计3.1.1 系统概述3.1.2 系统框图 3…

核心HTML5/CSS3基础面试题

HTML5/CSS3 高频经典面试题 汇总了 2023 年各互联网大厂以及中小型创业公司基础阶段的最新高频面试题 HTML/HTML5 标签 Interview questions 1、说说你对 HTML 语义化的理解 ?HTML5 新增了哪些语义化标签 ?(字节、百度,阿里,腾讯、京东,小米) 2、DOCTYPE 是干嘛的,…

一篇文章入门傅里叶变换

文章目录 傅里叶变换欧拉公式傅里叶变换绕圈记录法质心记录法傅里叶变换公式第一步&#xff1a;旋转的表示第二步&#xff1a;缠绕的表示第三步&#xff1a;质心的表示最终步&#xff1a;整理积分限和系数 参考文献 傅里叶变换 在学习傅里叶变换之前&#xff0c;我们先来了解一…

ubuntu df -h分配的磁盘空间小于物理磁盘

1. 检查卷组的可用空间 运行以下命令查看卷组的大小和空闲空间&#xff1a; vgdisplay或者&#xff1a; sudo vgs看一下是否有多余的空间未分配给逻辑卷。 2. 扩展逻辑卷 假设 ubuntu--vg-ubuntu--lv 是你想扩展的逻辑卷名称&#xff0c;运行以下命令将空闲空间分配到该逻…

OBOO鸥柏丨液晶拼接大屏分布式基本管理系统架构显示技术曝光

鸥柏分布式(WControl)分布式集中管控系统软件坐席功能输入/输出节点可将音视频信号转换成网络信号进行远程传输&#xff0c;KVM服务器极致的客户端体验操控&#xff0c;支持各大主流操作系统及国产操作系统&#xff0c;OBOO鸥柏液晶拼接大屏&#xff0c;触摸屏查询一体机&#…