设计模式-结构型模式(详解)

适配器模式

将一个类的接口转换成客户端期望的另一个接口,解决接口不兼容问题。

适配器模式由四部分组成:

  1. 客户端:即需要使用目标接口的类

  2. 目标接口

  3. 需要适配的类,也就是已经存在好的功能,但客户端通过目标接口没办法使用这个类

  4. 适配器,会实现目标接口,然后耦合需要适配的类,调用类的功能

分为类适配器和对象适配器

// 目标接口
public interface Target {void request();
}
// 适配者类
public class Adaptee {public void specificRequest() {System.out.println("Adaptee's specificRequest");}
}
// 类适配器
public class Adapter extends Adaptee implements Target {@Overridepublic void request() {specificRequest();}
}// 客户端代码
public class Client {public static void main(String[] args) {Target target = new Adapter();target.request();  // Output: Adaptee's specificRequest}
}

对象适配器: 通过组合,让适配器类持有现有类的实例,并实现目标接口**。对象适配器使用组合关系来实现接口的适配**,较为常用。

// 目标接口
public interface Target {void request();
}
// 适配者类
public class Adaptee {public void specificRequest() {System.out.println("Adaptee's specificRequest");}
}
// 对象适配器
public class Adapter implements Target {  //这里不再是和类适配器一样继承适配器,而是在类中装配适配器对象private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}
}// 客户端代码
public class Client {public static void main(String[] args) {Adaptee adaptee = new Adaptee();Target target = new Adapter(adaptee);target.request();  // Output: Adaptee's specificRequest}
}

Java 日志中的 slf4j 其实就是使用了适配器模式来统一不同日志框架接口,使得我们不需要修改代码就可以替换不同的底层日志实现。

桥接模式

主要的作用是将抽象和实现解耦,使它们可以独立地变化。

我们熟知的JDBC 就使用了桥接模式,JDBC定义了抽象的规范,不同的数据库厂商遵循这些规范,但是它们各自又会有不同的实现。
在使用中,如果我们数据库是 mysql,则传入 com.mysql.jdbc.Driver 驱动实现类,如果要换成 oracle替换实现类为oracle.jdbc.driver.OracleDriver 即可,这就是典型的抽象与实现解耦。

代码实例

实现形状颜色解耦

  1. 实现化(Implementor):定义颜色接口

    public interface Color {void applyColor();
    }
    
  2. 具体实现化(Concrete Implementor):实现具体颜色

    public class RedColor implements Color {@Overridepublic void applyColor() { System.out.println("Applying red color");  //红色}
    }public class BlueColor implements Color {   //蓝色@Overridepublic void applyColor() {System.out.println("Applying blue color");}
    }
    
  3. 抽象化(Abstraction):定义形状接口

    public abstract class Shape {protected Color color;public Shape(Color color) {this.color = color;}public abstract void draw();
    }
    
  4. 细化抽象化(Refined Abstraction):实现具体形状

    public class Circle extends Shape {public Circle(Color color) {super(color);}@Overridepublic void draw() {System.out.print("Drawing a circle with ");color.applyColor();}
    }public class Rectangle extends Shape {public Rectangle(Color color) {super(color);}@Overridepublic void draw() {System.out.print("Drawing a rectangle with ");color.applyColor();}
    }
    
  5. 客户端代码

    public class Client {public static void main(String[] args) {// 创建红色圆形Shape redCircle = new Circle(new RedColor());redCircle.draw();  // 输出: Drawing a circle with Applying red color// 创建蓝色矩形Shape blueRectangle = new Rectangle(new BlueColor());blueRectangle.draw();  // 输出: Drawing a rectangle with Applying blue color}
    }
    

组合模式

将对象组合成树状结构以表示“整体——部分”的层次关系

以部门为示例,展示组织内的部门和人员信息

// 抽象组织
interface OrganizationComponent {  void showDetails();
}// 组织人员
class Employee implements OrganizationComponent {private String name;private String position;public Employee(String name, String position) {this.name = name;this.position = position;}@Overridepublic void showDetails() {System.out.println("Employee: " + name + ", Position: " + position);}
}// 组织部门
class Department implements OrganizationComponent {private String name;private List<OrganizationComponent> components = new ArrayList<>();public Department(String name) {this.name = name;}@Overridepublic void showDetails() {System.out.println("Department: " + name);for (OrganizationComponent component : components) {component.showDetails();}}public void add(OrganizationComponent component) { //往部门添加人员 或 部门components.add(component);}public void remove(OrganizationComponent component) {components.remove(component);}
}// 使用代码
public class Client {public static void main(String[] args) {// 创建人员OrganizationComponent employee1 = new Employee("John Doe", "Developer");OrganizationComponent employee2 = new Employee("Jane Smith", "Designer");OrganizationComponent employee3 = new Employee("Emily Davis", "Manager");// 创建部门Department engineeringDepartment = new Department("Engineering Department");Department designDepartment = new Department("Design Department");Department headDepartment = new Department("Head Department");// 添加人员到部门engineeringDepartment.add(employee1);designDepartment.add(employee2);headDepartment.add(employee3);// 添加子部门到上级部门headDepartment.add(engineeringDepartment);headDepartment.add(designDepartment);// 显示整个组织结构的详情headDepartment.showDetails();// 输出// Department: Head Department// Employee: Emily Davis, Position: Manager// Department: Engineering Department// Employee: John Doe, Position: Developer// Department: Design Department// Employee: Jane Smith, Position: Designer}
}

通过组合模式,提供统一的接口,简化对层次结构的处理,使得使用方代码更加简洁与灵活。

装饰器模式

主要作用是通过创建包装类来实现功能的增强,而不是修改原始类

通过创建一个装饰器类,该类实现了与原始对象相同的接口,并持有一个原始对象的引用。通过将原始对象传递给装饰器

代理模式中,代理类附加的是跟原始类无关的功能,而在装饰器模式中,装饰器类附加的是跟原始类相关的增强功能。

最典型的装饰器实现就是 Java 中的I/O类库,示例代码如下:

import java.io.*;
public class IOExample {public static void main(String[] args) throws IOException {File file = new File("test.txt");FileInputStream fis = new FileInputStream(file);  //读取文件流BufferedInputStream bis = new BufferedInputStream(fis);  //fis被BufferedlnputStream 装饰,提供了缓存的功能DataInputStream dis = new DataInputStream(bis); //被 DatalnputStream 装饰,提供了按数据类型读取的功能while (dis.available() > 0) {System.out.println(dis.readLine());}dis.close();}
}

文件流的代码比较复杂,这里就不展示了,我们简单看个多装饰器叠加的代码实现:

// 组件
interface Component {void operation();
}// 具体构件
class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("ConcreteComponent operation");}
}// 装饰器
abstract class Decorator implements Component {protected Component component;   public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}
// 具体装饰器 A
class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedBehavior();}private void addedBehavior() {System.out.println("ConcreteDecoratorA added behavior");}
}
// 具体装饰器 B
class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedState();}private void addedState() {System.out.println("ConcreteDecoratorB added state");}
}// 客户端代码
public class Client {public static void main(String[] args) {Component component = new ConcreteComponent();Component decoratorA = new ConcreteDecoratorA(component);Component decoratorB = new ConcreteDecoratorB(decoratorA);decoratorB.operation();// Output:// ConcreteComponent operation// ConcreteDecoratorA added behavior// ConcreteDecoratorB added state}
}

外观模式

也叫门面模式,提供了一个简化的接口,用于访问复杂系统中的一组接口。将复杂系统的功能封装起来,让客户端可以更方便地使用系统功能而不需要了解其内部复杂结构。

举个例子就清晰了。例如 A系统有 a、b、c三个接口,B需要分别调用 a、b、c三个接口,这样比较麻烦,所以A将 a、b、c封装成一个接口给B调用,对B来说使用起来就方便了,这就是外观模式

class CPU {         //CPUpublic void start() {System.out.println("CPU 启动");}public void shutdown() {System.out.println("CPU 关闭");}
}
class Memory {            //内存public void start() {System.out.println("内存启动");}public void shutdown() {System.out.println("内存关闭");}
}class HardDrive {     //硬盘public void start() {System.out.println("硬盘启动");}public void shutdown() {System.out.println("硬盘关闭");}}
class ComputerFacade {         //外观类,封装了计算机系统的一组复杂接口,包括 CPU、内存和硬盘的启动和关闭private CPU cpu;private Memory memory;private HardDrive hardDrive;public ComputerFacade() {cpu = new CPU();memory = new Memory();hardDrive = new HardDrive();}public void start() {       //启动计算机System.out.println("计算机启动开始");cpu.start();memory.start();hardDrive.start();System.out.println("计算机启动完成");}public void shutdown() {    //关闭计算机System.out.println("计算机关闭开始");cpu.shutdown();memory.shutdown();hardDrive.shutdown();System.out.println("计算机关闭完成");}
}
ComputerFacade computerFacade = new ComputerFacade();
computerFacade.start();
// 输出:
// 计算机启动开始
// CPU 启动
// 内存启动
// 硬盘启动
// 计算机启动完成computerFacade.shutdown();
// 输出:
// 计算机关闭开始
// CPU 关闭
// 内存关闭
// 硬盘关闭
// 计算机关闭完成

享元模式

享元模式本质就是对象池,判断是否存在,若存在则取,不存在则添加。

Integer的缓存(-128~127)采用了享元模式。

具体原理可看 Java基础 29.什么是Java的Integer缓冲池?

示例:

假设我们要绘制棋盘上的棋子,棋子的种类有很多,但是每种棋子的形状和颜色是固定的。我们可以使用享元模式来共享相同种类的棋子对象,从而减少对象的创建数量。

// 棋子接口
interface ChessPiece {void setColor(String color);void display(int x, int y);
}
// 具体棋子类
class ConcreteChessPiece implements ChessPiece {private String color;public ConcreteChessPiece(String color) {this.color = color;}@Overridepublic void setColor(String color) {this.color = color;}@Overridepublic void display(int x, int y) {System.out.println("Chess Piece color: " + color + ", position: (" + x + "," + y + ")");}
}
// 享元工厂类
class ChessPieceFactory {private Map<String, ChessPiece> chessPieces;public ChessPieceFactory() {this.chessPieces = new HashMap<>();    //用集合存chessPieces}public ChessPiece getChessPiece(String color) {  //返回单例ChessPiece chessPiece = chessPieces.get(color);if (chessPiece == null) {chessPiece = new ConcreteChessPiece(color);chessPieces.put(color, chessPiece);}return chessPiece;}
}
// 客户端代码
public class Client {public static void main(String[] args) {ChessPieceFactory chessPieceFactory = new ChessPieceFactory();ChessPiece blackPiece1 = chessPieceFactory.getChessPiece("black");  ChessPiece blackPiece2 = chessPieceFactory.getChessPiece("black");ChessPiece whitePiece1 = chessPieceFactory.getChessPiece("white");ChessPiece whitePiece2 = chessPieceFactory.getChessPiece("white");blackPiece1.display(1, 2);  // 输出:Chess Piece color: black, position: (1,2)blackPiece2.display(3, 4);  // 输出:Chess Piece color: black, position: (3,4)whitePiece1.display(5, 6);  // 输出:Chess Piece color: white, position: (5,6)whitePiece2.display(7, 8);  // 输出:Chess Piece color: white, position: (7,8)}
}

代理模式

作用:在不改变原始类的情况下,为其提供一个代理,以控制对这个对象的访问

(代理模式和装饰器模式很像,其主要不同是,前者是控制原对象的访问,后者是为原对象增强已有类的功能)

核心是创建一个代理类,该类实现了与原始对象相同的接口,并持有一个原始对象的引用。在代理类的方法中,我们可以添加额外的功能,然后将请求转发给原始对象进行处理。

// 图片接口
interface Image {void display();
}
// 具体图片类
class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadImageFromDisk();}private void loadImageFromDisk() {System.out.println("Loading " + filename + " from disk.");}@Overridepublic void display() {System.out.println("Displaying " + filename);}
}
// 代理图片类
class ProxyImage implements Image {private RealImage realImage;   //引入具体图片类private String filename;		//实现了对原始图片对象的控制,而不需要修改原始图片类的代码public ProxyImage(String filename) {this.filename = filename;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(filename);}beforeDisplay();realImage.display();}private void beforeDisplay() {System.out.println("Before displaying " + filename + ", do some pre-processing.");}
}
// 客户端代码
public class Client {public static void main(String[] args) {Image image1 = new ProxyImage("image1.jpg");Image image2 = new ProxyImage("image2.jpg");image1.display();  // 输出:Before displaying image1.jpg, do some pre-processing.//        Loading image1.jpg from disk.//        Displaying image1.jpgimage2.display();  // 输出:Before displaying image2.jpg, do some pre-processing.//        Loading image2.jpg from disk.//        Displaying image2.jpg}
}

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

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

相关文章

银河麒麟操作系统下载

产品试用申请国产操作系统、麒麟操作系统——麒麟软件官方网站 下载页面链接如上&#xff0c;申请试用即可。 申请试用填写后提交&#xff0c;界面就变成了这样&#xff0c;可以挑选适合自己的版本。 海思麒麟9006C版&#xff0c;如下&#xff1a; 本地下载&#xff1a;Kylin…

[CARLA系列--03]如何打包生成CARLA 0.9.15的非编辑版(地图的加载与卸载)

前两篇文章介绍了如何去安装可编辑版的CARLA 0.9.15&#xff0c;这个完整的工程文件实在是太大了&#xff0c;大概消耗了100个G的磁盘空间&#xff0c;当在进行一个CARLA项目的时候&#xff0c;不利于在每个开发电脑都去安装部署一套CARLA 0.9.15的源码&#xff0c;所以把自己这…

【机器学习基础】机器学习入门核心算法:朴素贝叶斯(Naive Bayes)

机器学习入门核心算法&#xff1a;朴素贝叶斯&#xff08;Naive Bayes&#xff09;&#xff09; 一、算法逻辑1.1 基本概念1.2 基本流程 二、算法原理与数学推导2.1 贝叶斯定理2.2 朴素贝叶斯分类器2.3 不同分布假设下的概率计算2.3.1 高斯朴素贝叶斯&#xff08;连续特征&…

云服务器系统盘满了,但是其他正常,是否可能是被攻击了

目录 问题背景分析解决系统盘满的问题解决结果 问题背景 今天登录我的云服务器看了眼&#xff0c;发现系统盘满了&#xff0c;但是其他正常 分析 1、首先要确认是否是被攻击&#xff1a; top / htop (安装&#xff1a;yum install htop 或 apt install htop)&#xff1a;…

双因子COX 交互 共线性 -spss

SPSS 简要界面操作步骤(针对双因子 COX 分析) 1. 数据准备 变量格式:确保数据已整理为以下格式(示例): 时间变量(如 Time_to_Recurrence)结局变量(如 Recurrence:1=复发,0=未复发)预测变量(CSPG4_HSCORE、FAM49B_Status 二分类变量)协变量(如 Lesion_Size、Pat…

【MySQL】第12节|MySQL 8.0 主从复制原理分析与实战(二)

一、组复制&#xff08;MGR&#xff09;核心概念 1. 定义与定位 目标&#xff1a;解决传统主从复制的单点故障、数据不一致问题&#xff0c;提供高可用、高扩展的分布式数据库方案。基于 GTID&#xff1a;依赖全局事务标识符&#xff08;GTID&#xff09;实现事务一致性&…

React 泛型组件:用TS来打造灵活的组件。

文章目录 前言一、什么是泛型组件&#xff1f;二、为什么需要泛型组件&#xff1f;三、如何在 React 中定义泛型组件&#xff1f;基础泛型组件示例使用泛型组件 四、泛型组件的高级用法带默认类型的泛型组件多个泛型参数 五、泛型组件的实际应用场景数据展示组件表单组件状态管…

如何手搓一个查询天气的mcp server

环境配置烦请移步上一篇博客 这里直接步入主题&#xff0c;天气查询的api用的是openweather&#xff0c;免费注册就可以使用了 每天1000次内使用时免费的&#xff0c;大概的api 如下 https://api.openweathermap.org/data/2.5/weather?qBeijing,cn&APPID注册后可以拿到一个…

深入解析计算机网络核心协议:ARP、DHCP、DNS与HTTP

文章目录 一、ARP&#xff08;地址解析协议&#xff09;1.1 定义与功能1.2 工作原理1.3 应用场景1.4 安全风险与防御 二、DHCP&#xff08;动态主机配置协议&#xff09;2.1 定义与功能2.2 工作原理2.3 应用场景2.4 优缺点与安全建议 三、DNS&#xff08;域名系统&#xff09;3…

《Java 单例模式:从类加载机制到高并发设计的深度技术剖析》

【作者简介】“琢磨先生”--资深系统架构师、985高校计算机硕士&#xff0c;长期从事大中型软件开发和技术研究&#xff0c;每天分享Java硬核知识和主流工程技术&#xff0c;欢迎点赞收藏&#xff01; 一、单例模式的核心概念与设计目标 在软件开发中&#xff0c;我们经常会遇…

NL2SQL代表,Vanna

Vanna 核心功能、应用场景与技术特性详解 一、核心功能 1. 自然语言转SQL查询 Vanna 允许用户通过自然语言提问&#xff08;如“显示2024年销售额最高的产品”&#xff09;&#xff0c;自动生成符合数据库规范的SQL查询语句。其底层采用 RAG&#xff08;检索增强生成&#xf…

【动态规划】子数组系列(二)

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人的动态规划算法学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码&#xff1b;&…

68元开发板,开启智能硬件新篇章——明远智睿SSD2351深度解析

在智能硬件开发领域&#xff0c;开发板的选择至关重要。它不仅关系到项目的开发效率&#xff0c;还直接影响到最终产品的性能与稳定性。而今天&#xff0c;我要为大家介绍的这款明远智睿SSD2351开发板&#xff0c;仅需68元&#xff0c;却拥有远超同价位产品的性能与功能&#x…

篇章六 数据结构——链表(二)

目录 1. LinkedList的模拟实现 1.1 双向链表结构图​编辑 1.2 三个简单方法的实现 1.3 头插法 1.4 尾插法 1.5 中间插入 1.6 删除 key 1.7 删除所有key 1.8 clear 2.LinkedList的使用 2.1 什么是LinkedList 5.2 LinkedList的使用 1.LinkedList的构造 2. LinkedList的…

删除队列中整数

给定一个长度为N的整数数列A_1,A_2,...,A_N&#xff0c;请重复以下操作K次。 每次选择数列中最小的整数&#xff08;如果最小值不止一个&#xff0c;选择最靠前的&#xff09;&#xff0c;将其删除&#xff0c;并把与它相邻的整数加上被删除的数值。 请问K次操作后的序列是什…

[神经网络]使用olivettiface数据集进行训练并优化,观察对比loss结果

结合归一化和正则化来优化网络模型结构&#xff0c;观察对比loss结果 搭建的神经网络&#xff0c;使用olivettiface数据集进行训练&#xff0c;结合归一化和正则化来优化网络模型结构&#xff0c;观察对比loss结果 from sklearn.datasets import fetch_olivetti_faces #倒入数…

算法分析·回溯法

回溯法 方法概述算法框架问题实例TSP 问题n皇后问题 回溯法效率分析 方法概述 回溯法是一个既带有系统性又带有跳跃性的搜索算法&#xff1b; **系统性&#xff1a;**它在包含问题的所有解的解空间树中&#xff0c;按照深度优先的策略&#xff0c;从根结点出发搜索解空间树。…

Golang分布式系统开发实践指南

Golang分布式系统开发实践指南 一、为什么选择Golang&#xff1f; ​原生并发模型​ Goroutine和Channel机制天然适合分布式系统的并发需求​高性能编译​ 静态编译生成二进制文件&#xff0c;部署简单&#xff0c;内存占用低​丰富生态​ Go Module管理、标准库支持HTTP/2、…

基于stm32风速风向温湿度和瓦斯检测(仿真+代码)

资料下载地址&#xff1a;基于stm32风速风向温湿度和瓦斯检测 一、项目功能 1.风速&#xff0c;风向&#xff0c;温湿度&#xff0c;瓦斯&#xff0c;报警。 2.可以设置温湿度&#xff0c;瓦斯&#xff0c;风速报警阈值。 3.数据上传到云平台。 二、仿真图 三、程序 #inc…

桃黑黑反斗战

1.编写求解Hanoi汉诺塔的递归算法代码&#xff0c;输出移动过程&#xff0c;并统计总移动次数。 对不同规模的汉诺塔&#xff0c;给出测试的结果 #include <stdio.h> #include <time.h> int moveCount 0; void hanoi(int n,char source,char auxiliary,char targ…