当前位置: 首页 > 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 }]} ]要渲染为下面…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...