当前位置: 首页 > news >正文

万字解析设计模式之 装饰者模式

一·、装饰者模式

1.1概述

装饰者模式是一种结构型设计模式,它允许在运行时动态地为一个对象添加额外的职责。它以一种透明的方式来扩展对象的功能,而不需要通过子类来实现。在装饰者模式中,有一个基本对象,也称为组件,它可以被一个或多个装饰器包装。装饰器不改变基本对象本身的行为,而是在基本对象的行为之前或之后添加一些额外的行为。这样可以轻松地构建出复杂的对象,而不需要使用大量的子类。

动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活

我们先来看一个快餐店的例子。

快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦。

使用继承的方式存在的问题:

  • 扩展性不好

    如果要再加一种配料(火腿肠),我们就会发现需要给FriedRice和FriedNoodles分别定义一个子类。如果要新增一个快餐品类(炒河粉)的话,就需要定义更多的子类。

  • 产生过多的子类

1.2结构

装饰(Decorator)模式中的角色:

  • 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  • 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

 1.3实现

我们使用装饰者模式对快餐店案例进行改进,体会装饰者模式的精髓。

类图如下:

抽象组件

package com.yanyu.Decorator;// 定义一个抽象组件类,即快餐接口,包括价格和描述
public abstract class FastFood {private float price;  // 定义价格private String desc;  // 定义描述public FastFood() {}public FastFood(float price, String desc) {  // 构造函数,传入价格和描述this.price = price;this.desc = desc;}public void setPrice(float price) {  // 设置价格this.price = price;}public float getPrice() {  // 获取价格return price;}public String getDesc() {  // 获取描述return desc;}public void setDesc(String desc) {  // 设置描述this.desc = desc;}public abstract float cost();  // 获取价格的抽象方法
}

具体构件;

package com.yanyu.Decorator;//炒饭
public class FriedRice extends FastFood {public FriedRice() {super(10, "炒饭");}public float cost() {return getPrice();}
}
package com.yanyu.Decorator;//炒面
public class FriedNoodles extends FastFood {public FriedNoodles() {super(12, "炒面");}public float cost() {return getPrice();}
}

抽象装饰者

package com.yanyu.Decorator;// 定义一个抽象装饰者类,即配料类,继承自快餐接口
public abstract class Garnish extends FastFood {private FastFood fastFood;  // 定义一个快餐接口类型的对象,即被装饰的组件public FastFood getFastFood() {  // 获取被装饰的组件return fastFood;}public void setFastFood(FastFood fastFood) {  // 设置被装饰的组件this.fastFood = fastFood;}public Garnish(FastFood fastFood, float price, String desc) {  // 构造函数,传入被装饰的组件、价格和描述super(price, desc);  // 调用父类的构造函数,初始化价格和描述this.fastFood = fastFood;  // 初始化被装饰的组件}
}

具体装饰者

package com.yanyu.Decorator;//鸡蛋配料
public class Egg extends Garnish {public Egg(FastFood fastFood) {super(fastFood,1,"鸡蛋");}public float cost() {return getPrice() + getFastFood().getPrice();}@Overridepublic String getDesc() {return super.getDesc() + getFastFood().getDesc();}
}
package com.yanyu.Decorator;//培根配料
public class Bacon extends Garnish {public Bacon(FastFood fastFood) {super(fastFood,2,"培根");}@Overridepublic float cost() {return getPrice() + getFastFood().getPrice();}@Overridepublic String getDesc() {return super.getDesc() + getFastFood().getDesc();}
}

客户端类

// 测试类
public class Client {public static void main(String[] args) {// 点一份炒饭FastFood food = new FriedRice();// 花费的价格System.out.println(food.getDesc() + " " + food.cost() + "元");System.out.println("========");// 点一份加鸡蛋的炒饭FastFood food1 = new FriedRice();food1 = new Egg(food1);  // 使用装饰者模式给炒饭加上鸡蛋// 花费的价格System.out.println(food1.getDesc() + " " + food1.cost() + "元");System.out.println("========");// 点一份加培根的炒面FastFood food2 = new FriedNoodles();food2 = new Bacon(food2);  // 使用装饰者模式给炒面加上培根// 花费的价格System.out.println(food2.getDesc() + " " + food2.cost() + "元");}
}

好处:

  • 饰者模式可以带来比继承更加灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性,完美的遵循开闭原则,继承是静态的附加责任,装饰者则是动态的附加责任。
  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

1.4使用场景

  • 如果你希望在无需修改代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为, 可以使用装饰模式。

装饰能将业务逻辑组织为层次结构, 你可为各层创建一个装饰, 在运行时将各种不同逻辑组合成对象。 由于这些对象都遵循通用接口, 客户端代码能以相同的方式使用这些对象。

  • 如果用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用该模式。

许多编程语言使用 final最终关键字来限制对某个类的进一步扩展。 复用最终类已有行为的唯一方法是使用装饰模式: 用封装器对其进行封装。

1.5JDK源码解析

装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许我们动态地给一个对象添加额外的行为,是继承关系的一种替代方案。

在 JDK 中,装饰者模式被广泛地使用,比如 `java.io` 包中的输入输出流就是一个很好的例子。在这个包中,`InputStream` 和 `OutputStream` 是抽象基类,它们定义了基本的输入输出操作。`FilterInputStream` 和 `FilterOutputStream` 是装饰者类,它们继承了基类并添加了额外的行为,比如缓冲读写、数据压缩等。下面以 `BufferedInputStream` 为例进行介绍。

public class BufferedInputStream extends FilterInputStream {protected volatile byte buf[];protected int count;protected int pos;protected int markpos = -1;protected int marklimit;// ...public BufferedInputStream(InputStream in) {this(in, DEFAULT_BUFFER_SIZE);}public BufferedInputStream(InputStream in, int size) {super(in);if (size <= 0) {throw new IllegalArgumentException("Buffer size <= 0");}buf = new byte[size];}// ...}

可以看到,`BufferedInputStream` 继承了 `FilterInputStream`,并重载了 `InputStream` 的部分方法。它包含一个字节数组 `buf`,用来缓存输入数据,从而减少底层输入流的读取次数,提高效率。

public class FilterInputStream extends InputStream {protected volatile InputStream in;protected FilterInputStream(InputStream in) {this.in = Objects.requireNonNull(in);}// ...}

`FilterInputStream` 和 `FilterOutputStream` 都是抽象类,它们继承了基类并添加了构造函数和 `in` 或 `out` 属性,用于保存被装饰的基础流。

在这个例子中,`BufferedInputStream` 充当了装饰者的角色,它在 `InputStream` 的基础上添加了缓存的功能,从而满足了更加复杂的输入需求。这个模式让我们能够在运行时动态地添加或修改对象的行为,而不需要修改原始对象的代码。

1.6代理和装饰者的区别

静态代理和装饰者模式的区别:

  • 相同点:

    • 都要实现与目标类相同的业务接口
    • 在两个类中都要声明目标对象
    • 都可以在不修改目标类的前提下增强目标方法
  • 不同点:

    • 目的不同 装饰者是为了增强目标对象 静态代理是为了保护和隐藏目标对象
    • 获取目标对象构建的地方不同 装饰者是由外界传递进来,可以通过构造方法传递 静态代理是在代理类内部创建,以此来隐藏目标对象

 

 二、装饰者模式实验

任务描述

某系统的读写文件模块,最初的业务逻辑类仅能读取和写入纯文本的数据。 现状系统需要进行安全升级,写数据需要先压缩再加密,读数据需要先解压缩再解密还原。

本关任务:用装饰模式加强原来的文件读写模块。第一个封装器负责加密和解密数据, 而第二个则负责压缩和解压数据。

实现方式

  1. 确保业务逻辑可用一个基本组件及多个额外可选层次表示;

  2. 找出基本组件和可选层次的通用方法。 创建一个组件接口并在其中声明这些方法;

  3. 创建一个具体组件类, 并定义其基础行为;

  4. 创建装饰基类, 使用一个成员变量存储指向被封装对象的引用。 该成员变量必须被声明为组件接口类型, 从而能在运行时连接具体组件和装饰。 装饰基类必须将所有工作委派给被封装的对象;

  5. 确保所有类实现组件接口;

  6. 将装饰基类扩展为具体装饰。 具体装饰必须在调用父类方法 (总是委派给被封装对象) 之前或之后执行自身的行为;

  7. 客户端代码负责创建装饰并将其组合成客户端所需的形式。

编程提示

//压缩函数String compress(String stringData) {byte[] data = stringData.getBytes();try {ByteArrayOutputStream bout = new ByteArrayOutputStream(512);DeflaterOutputStream dos = new DeflaterOutputStream(bout, new Deflater(compLevel));dos.write(data);dos.close();bout.close();return Base64.getEncoder().encodeToString(bout.toByteArray());} catch (IOException ex) {return null;}}
//解压缩函数String decompress(String stringData) {byte[] data = Base64.getDecoder().decode(stringData);try {InputStream in = new ByteArrayInputStream(data);InflaterInputStream iin = new InflaterInputStream(in);ByteArrayOutputStream bout = new ByteArrayOutputStream(512);int b;while ((b = iin.read()) != -1) {bout.write(b);}in.close();iin.close();bout.close();return new String(bout.toByteArray());} catch (IOException ex) {return null;}}
 //加密函数String encode(String data) {byte[] result = data.getBytes();for (int i = 0; i < result.length; i++) {result[i] += (byte) 1;}return Base64.getEncoder().encodeToString(result);}
//解密函数String decode(String data) {byte[] result = Base64.getDecoder().decode(data);for (int i = 0; i < result.length; i++) {result[i] -= (byte) 1;}return new String(result);}

编程要求

根据提示,在右侧编辑器 Begin-End 内补充代码: DataSource:抽象读写构件类; FileDataSource:具体文件读写构件类; DataSourceDecorator:抽象装饰类; CompressionDecorator:具体的字符串压缩/解压缩装饰类; EncryptionDecorator:具体的字符串加密/解密装饰类。

"DataSourceDecorator.java"、"CompressionDecorator.java" 和 "EncryptionDecorator.java",请补全文件中的代码,其它文件的代码不需要修改。

测试说明

平台会自动从文件中读取数据,然后对你编写的代码进行测试:

预期输出: Input ---------------- user,password John100000 Steven912000 Encoded -------------- Zkt4c01WNXUxam1KTUQ1dnt6Okw1Z01Mezloe09CQkNzdkRUMk1NVlFGdUVKekJJQlFjbEQ5Uj4= Decoded -------------- user,password John100000 Steven912000

抽象构件

package step1;// 定义数据源接口,包含写入数据和读取数据的方法
public interface DataSource {void writeData(String data);String readData();
}

具体构件

package step1;import java.io.*;// 具体组件,实现了数据源接口
public class FileDataSource implements DataSource {private String name;public FileDataSource(String name) {this.name = name;}@Overridepublic void writeData(String data) {// 将数据写入文件File file = new File(name);try (OutputStream fos = new FileOutputStream(file)) {fos.write(data.getBytes(), 0, data.length());} catch (IOException ex) {System.out.println(ex.getMessage());}}@Overridepublic String readData() {// 从文件中读取数据char[] buffer = null;File file = new File(name);try (FileReader reader = new FileReader(file)) {buffer = new char[(int) file.length()];reader.read(buffer);} catch (IOException ex) {System.out.println(ex.getMessage());}return new String(buffer);}
}

抽象装饰

package step1;// 定义一个抽象装饰者类
public abstract class DataSourceDecorator implements DataSource {protected DataSource datasource; // 被装饰的数据源对象// 获取被装饰的组件public DataSource getDataSource() {return datasource;}// 设置被装饰的组件public void setDataSource(DataSource datasource) {this.datasource = datasource;}// 构造方法,接受被装饰的数据源对象public DataSourceDecorator(DataSource datasource) {this.datasource = datasource;}// 实现数据源接口中的读取数据方法@Overridepublic String readData() {return datasource.readData();}// 实现数据源接口中的写入数据方法@Overridepublic void writeData(String data) {datasource.writeData(data);}
}

具体装饰

package step1;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;public class CompressionDecorator extends DataSourceDecorator {private int compLevel = 6; // 压缩级别,默认为6public CompressionDecorator(DataSource datasource) {super(datasource);}public int getCompressionLevel() {return compLevel;}public void setCompressionLevel(int value) {compLevel = value;}@Overridepublic String readData() {// 对读取的数据进行解压缩return decompress(datasource.readData());}@Overridepublic void writeData(String data) {// 对写入的数据进行压缩datasource.writeData(compress(data));}private String compress(String stringData) {// 使用压缩函数对字符串进行压缩byte[] data = stringData.getBytes();try {ByteArrayOutputStream bout = new ByteArrayOutputStream(512);DeflaterOutputStream dos = new DeflaterOutputStream(bout, new Deflater(compLevel));dos.write(data);dos.close();bout.close();return Base64.getEncoder().encodeToString(bout.toByteArray());} catch (IOException ex) {return null;}}private String decompress(String stringData) {// 使用解压缩函数对字符串进行解压缩byte[] data = Base64.getDecoder().decode(stringData);try {InputStream in = new ByteArrayInputStream(data);InflaterInputStream iin = new InflaterInputStream(in);ByteArrayOutputStream bout = new ByteArrayOutputStream(512);int b;while ((b = iin.read()) != -1) {bout.write(b);}in.close();iin.close();bout.close();return new String(bout.toByteArray());} catch (IOException ex) {return null;}}
}
package step1;import java.util.Base64;// 具体装饰者类,实现了数据加密和解密功能
public class EncryptionDecorator extends DataSourceDecorator {// 构造方法,接收被装饰的数据源对象public EncryptionDecorator(DataSource datasource) {super(datasource);}// 重写读取数据方法,对读取的数据进行解密操作@Overridepublic String readData() {String encryptedData = datasource.readData();return decode(encryptedData);}// 重写写入数据方法,对写入的数据进行加密操作@Overridepublic void writeData(String data) {String encryptedData = encode(data);datasource.writeData(encryptedData);}// 加密方法,使用加密函数对字符串进行加密private String encode(String data) {byte[] result = data.getBytes();for (int i = 0; i < result.length; i++) {result[i] += (byte) 1;}return Base64.getEncoder().encodeToString(result);}// 解密方法,使用解密函数对字符串进行解密private String decode(String data) {byte[] result = Base64.getDecoder().decode(data);for (int i = 0; i < result.length; i++) {result[i] -= (byte) 1;}return new String(result);}
}

客户端类

package step1;import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;public class XMLUtils {public static String getBean(String name) {try {//创建DOM文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;doc = builder.parse(new File("/data/workspace/myshixun/src/config.xml"));//获取包含类名的文本结点NodeList nl = doc.getElementsByTagName(name);Node classNode = nl.item(0).getFirstChild();String value = classNode.getNodeValue();return value;}catch(Exception e) {e.printStackTrace();return null;}}
}
package step1;public class Client {public static void main(String[] args) {// 从XML配置文件中获取薪资记录和文件路径String salaryRecords = XMLUtils.getBean("stringValue");String filePath = XMLUtils.getBean("filePath");// 创建一个装饰者对象,先进行加密再进行压缩,最后写入文件DataSourceDecorator encoded = new CompressionDecorator(new EncryptionDecorator(new FileDataSource(filePath)));encoded.writeData(salaryRecords);// 创建一个普通的数据源对象,用于输出原始数据DataSource plain = new FileDataSource(filePath);// 输出原始薪资记录System.out.println("Input ----------------");System.out.println(salaryRecords);// 输出经过装饰者加密和压缩后的数据System.out.println("Encoded --------------");System.out.println(plain.readData());// 输出经过装饰者解密和解压缩后的数据System.out.println("Decoded --------------");System.out.println(encoded.readData());}
}

 

任务描述
某系统的读写文件模块,最初的业务逻辑类仅能读取和写入纯文本的数据。 现状系统需要进行安全升级,写数据需要先压缩再加密,读数据需要先解压缩再解密还原。本关任务:用装饰模式加强原来的文件读写模块。第一个封装器负责加密和解密数据, 而第二个则负责压缩和解压数据。实现方式
确保业务逻辑可用一个基本组件及多个额外可选层次表示;找出基本组件和可选层次的通用方法。 创建一个组件接口并在其中声明这些方法;创建一个具体组件类, 并定义其基础行为;创建装饰基类, 使用一个成员变量存储指向被封装对象的引用。 该成员变量必须被声明为组件接口类型, 从而能在运行时连接具体组件和装饰。 装饰基类必须将所有工作委派给被封装的对象;确保所有类实现组件接口;将装饰基类扩展为具体装饰。 具体装饰必须在调用父类方法 (总是委派给被封装对象) 之前或之后执行自身的行为;客户端代码负责创建装饰并将其组合成客户端所需的形式。编程提示
//压缩函数String compress(String stringData) {byte[] data = stringData.getBytes();try {ByteArrayOutputStream bout = new ByteArrayOutputStream(512);DeflaterOutputStream dos = new DeflaterOutputStream(bout, new Deflater(compLevel));dos.write(data);dos.close();bout.close();return Base64.getEncoder().encodeToString(bout.toByteArray());} catch (IOException ex) {return null;}}
//解压缩函数String decompress(String stringData) {byte[] data = Base64.getDecoder().decode(stringData);try {InputStream in = new ByteArrayInputStream(data);InflaterInputStream iin = new InflaterInputStream(in);ByteArrayOutputStream bout = new ByteArrayOutputStream(512);int b;while ((b = iin.read()) != -1) {bout.write(b);}in.close();iin.close();bout.close();return new String(bout.toByteArray());} catch (IOException ex) {return null;}}//加密函数String encode(String data) {byte[] result = data.getBytes();for (int i = 0; i < result.length; i++) {result[i] += (byte) 1;}return Base64.getEncoder().encodeToString(result);}
//解密函数String decode(String data) {byte[] result = Base64.getDecoder().decode(data);for (int i = 0; i < result.length; i++) {result[i] -= (byte) 1;}return new String(result);}
编程要求
根据提示,在右侧编辑器 Begin-End 内补充代码:
DataSource:抽象读写构件类;
FileDataSource:具体文件读写构件类;
DataSourceDecorator:抽象装饰类;
CompressionDecorator:具体的字符串压缩/解压缩装饰类;
EncryptionDecorator:具体的字符串加密/解密装饰类。"DataSourceDecorator.java"、"CompressionDecorator.java" 和 "EncryptionDecorator.java",请补全文件中的代码,其它文件的代码不需要修改。

相关文章:

万字解析设计模式之 装饰者模式

一、装饰者模式 1.1概述 装饰者模式是一种结构型设计模式&#xff0c;它允许在运行时动态地为一个对象添加额外的职责。它以一种透明的方式来扩展对象的功能&#xff0c;而不需要通过子类来实现。在装饰者模式中&#xff0c;有一个基本对象&#xff0c;也称为组件&#xff0c;…...

生成对抗网络Generative Adversarial Network,GAN

Basic Idea of GAN Generation&#xff08;生成器&#xff09;  Generation是一个neural network&#xff0c;它的输入是一个vector&#xff0c;它的输出是一个更高维的vector&#xff0c;以图片生成为例&#xff0c;输出就是一张图片&#xff0c;其中每个维度的值代表生…...

C++入门第八篇---STL模板---list的模拟实现

前言&#xff1a; 有了前面的string和vector两个模板的基础&#xff0c;我们接下来就来模拟实现一下list链表模板&#xff0c;我还是要强调的一点是&#xff0c;我们模拟实现模板的目的是熟练的去使用以及去学习一些对于我们本身学习C有用的知识和用法&#xff0c;而不是单纯的…...

论文导读 | 大语言模型与知识图谱复杂逻辑推理

前 言 大语言模型&#xff0c;尤其是基于思维链提示词&#xff08;Chain-of Thought Prompting&#xff09;[1]的方法&#xff0c;在多种自然语言推理任务上取得了出色的表现&#xff0c;但不擅长解决比示例问题更难的推理问题上。本文首先介绍复杂推理的两个分解提示词方法&a…...

数智竞技何以成为“科技+体育”新样本?

文 | 智能相对论 作者 | 青月 “欢迎来到&#xff0c;钢铁突袭。” 三人一组&#xff0c;头戴VR设备&#xff0c;中国香港队和泰国队在数实融合的空间里捉对厮杀&#xff0c;通过互相射击对方能量铠甲获取积分。 虽然双方都展现出了极强的机动性&#xff0c;但显然中国香港队…...

Vue项目Jenkins自动化部署

1. 需求描述 我们希望提交uat分支时,UAT项目能够自动发布,提交master分支时,无需自动发布,管理员手工发布 2. 效果展示 3. 采用技术 Jenkins + K8S + Docker + Nginx 4. 具体实现 4.1 编写default.conf 在Vue项目根目录新建default.conf文件,主要进行代理配置、首页…...

特效!视频里的特效在哪制作——Adobe After Effects

今天&#xff0c;我们来谈谈一款在Adobe系列中推出的一款图形视频处理软件&#xff0c;适用于从事设计和视频特技的机构&#xff0c;包括电视台、动画制作公司、个人后期制作工作室以及多媒体工作室的属于层类型后期软件——Adobe After Effects。 Adobe After Effects&#xf…...

2023年中国醇酸树脂涂料需求量、应用领域及市场规模前景分析[图]

醇酸树脂指多元醇和多元酸与脂肪酸经过酯化缩聚生成的高聚物&#xff0c;其由邻苯二甲酸酐、多元醇和脂肪酸或甘油三脂肪酸酯缩合聚合而成。醇酸树脂固化成膜后&#xff0c;具有耐磨性好、绝缘性佳等优势&#xff0c;在涂料领域应用广泛。2022年醇酸树脂产量约336.3万吨&#x…...

【Linux进阶之路】动静态库

文章目录 回顾一. 静态库1.代码传递的方式2.简易制作3.原理 二. 动态库1.简易制作2.基本原理 尾序 回顾 前面在gcc与g的使用中&#xff0c;我们简单的介绍了动态库与静态库的各自的优点与区别&#xff1a; 动态链接库&#xff0c;也就是所有的程序公用一份代码,虽然方便省空间&…...

Ubuntu磁盘扩展容量

gparted扩展...

2023年中国羽绒制品需求现状、市场规模及细分产品规模分析[图]

羽绒羽毛指生长在水禽类动物&#xff08;鹅、鸭&#xff09;腋下、腹部羽绒和羽毛的统称&#xff0c;属于上游鹅鸭肉食品工业副产品的综合利用&#xff0c;是下游羽绒制品的填充料。根据国家标准&#xff0c;绒子含量≥50%的称为羽绒&#xff0c;绒子含量&#xff1c;50%的称为…...

动手学深度学习——循环神经网络的从零开始实现(原理解释+代码详解)

文章目录 循环神经网络的从零开始实现1. 独热编码2. 初始化模型参数3. 循环神经网络模型4. 预测5. 梯度裁剪6. 训练 循环神经网络的从零开始实现 从头开始基于循环神经网络实现字符级语言模型。 # 读取数据集 %matplotlib inline import math import torchfrom torch import …...

【操作系统】文件系统的逻辑结构与目录结构

文章目录 文件的概念定义属性基本操作 文件的结构文件的逻辑结构文件的目录结构文件控制块&#xff08;FCB&#xff09;索引节点目录结构 文件的概念 定义 在操作系统中&#xff0c;文件被定义为&#xff1a;以计算机硬盘为载体的存储在计算机上的信息集合。 属性 描述文件…...

局域网内Ubuntu上搭建Git服务器

1.在局域网内选定一台Ubuntu电脑作为Git服务端&#xff1a; (1).新建用户如为fbc&#xff0c;执行如下命令&#xff1a;需设置密码&#xff0c;此为fbc sudo adduser fbc (2).切换到fbc用户&#xff1a;需密码&#xff0c;此前设置为fbc su fbc (3).建一个空目录作为仓…...

基础课10——自然语言生成

自然语言生成是让计算机自动或半自动地生成自然语言的文本。这个领域涉及到自然语言处理、语言学、计算机科学等多个领域的知识。 1.简介 自然语言生成系统可以分为基于规则的方法和基于统计的方法两大类。基于规则的方法主要依靠专家知识库和语言学规则来生成文本&#xff0…...

xpath

xpath 使用 使用 from lxml import etree或者 from lxml import htmlet etree.XML(xml) et etree.HTML(html) res et.xpath("/book") # 返回列表项目Valueet.xpath(“/book”)/表示根节点/div/a子节点用/依次表示/name/text()text()取文本/book//nick//表示标签…...

Java拼图小游戏

Java拼图小游戏 import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collections; import java.util.List;public cla…...

终于有人把数据资产入表知识地图总结出来了,轻松看懂

在当前数字化的浪潮下&#xff0c;数据已经成为劳动、土地、知识、技术以后的第五大生产要素&#xff0c;“数据就是资源”已成为共识。如今数据资产“入表”已成定局&#xff0c;数据资产化迫在眉睫。 2023年8月21日&#xff0c;财政部正式印发《企业数据资源相关会计处理暂行…...

白鳝:聊聊IvorySQL的Oracle兼容技术细节与实现原理

两年前听瀚高的一个朋友说他们要做一个开源数据库项目&#xff0c;基于PostgreSQL&#xff0c;主打与Oracle的兼容性&#xff0c;并且与PG社区版内核同步发布。当时我听了有点不太相信&#xff0c;瀚高的Highgo是在PG内核上增加了一定的Oracle兼容性的特性&#xff0c;一般也会…...

vue和uni-app的递归组件排坑

有这样一个数组数据&#xff0c;实际可能有很多级。 tree: [{id: 1,name: 1,children: [{ id: 2, name: 1-1, children: [{id: 7, name: 1-1-1,children: []}]},{ id: 3, name: 1-2 }]},{id: 4,name: 2,children: [{ id: 5, name: 2-1 },{ id: 6, name: 2-2 }]} ]要渲染为下面…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集&#xff0c;单周期执行&#xff1b;低功耗、CIP 独立外设&#xff1b;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel&#xff08;原始…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解

文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...

C++ 类基础:封装、继承、多态与多线程模板实现

前言 C 是一门强大的面向对象编程语言&#xff0c;而类&#xff08;Class&#xff09;作为其核心特性之一&#xff0c;是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性&#xff0c;包括封装、继承和多态&#xff0c;同时讨论类中的权限控制&#xff0c;并展示如何使用类…...

Axure Rp 11 安装、汉化、授权

Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接&#xff1a;https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...

RKNN开发环境搭建2-RKNN Model Zoo 环境搭建

目录 1.简介2.环境搭建2.1 启动 docker 环境2.2 安装依赖工具2.3 下载 RKNN Model Zoo2.4 RKNN模型转化2.5编译C++1.简介 RKNN Model Zoo基于 RKNPU SDK 工具链开发, 提供了目前主流算法的部署例程. 例程包含导出RKNN模型, 使用 Python API, CAPI 推理 RKNN 模型的流程.   本…...

比较数据迁移后MySQL数据库和ClickHouse数据仓库中的表

设计一个MySQL数据库和Clickhouse数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...