设计模式系列(08):创建型模式 - 原型模式

系列导读:完成创建型模式的学习,我们来看最后一个创建型模式——原型模式。它通过复制已有对象来创建新对象,是一种独特的创建方式。

解决什么问题:通过复制现有对象来创建新对象,而不是重新实例化。适用于对象创建成本高、需要保持状态的场景。

在实际开发中,有时候创建一个对象的成本很高,比如需要从数据库查询大量数据、进行复杂计算、或者建立网络连接等。如果需要创建多个相似的对象,每次都重新执行这些操作就太浪费了。

原型模式提供了一个聪明的解决方案:先创建一个原型对象,然后通过复制这个原型来创建新对象。这样既保留了对象的状态,又避免了重复的创建成本。

本文在系列中的位置

  • 前置知识:建造者模式
  • 系列角色:创建型模式收尾
  • 难度等级:★★★☆☆(需要理解深拷贝和浅拷贝)
  • 后续学习:结构型模式:适配器模式

目录

  • 1. 模式概述
  • 2. 使用场景
  • 3. 优缺点分析
  • 4. 实际应用案例
  • 5. 结构与UML类图
  • 6. 代码示例
  • 7. 测试用例
  • 8. 常见误区与反例
  • 9. 最佳实践
  • 10. 参考资料与延伸阅读

1. 模式概述

原型模式(Prototype Pattern)是一种创建型设计模式。它通过克隆现有对象来创建新对象,而不是通过实例化类来创建。适用于对象创建成本高、状态复杂或需批量复制的场景。

1.1 定义

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

1.2 目的

  • 对象复制,提升效率
  • 避免子类膨胀,简化扩展
  • 支持动态配置和运行时扩展

2. 使用场景

原型模式在实际开发中应用广泛,常见场景包括:

  1. 文档/模板复制:如Word、PPT、设计稿等模板批量生成。
  2. 游戏开发:如角色、道具、场景等对象池批量克隆。
  3. 缓存/对象池:如数据库连接、线程、任务等对象池管理。
  4. 配置/环境克隆:如系统配置、环境参数的快速复制。

真实业务背景举例:

  • OA系统支持一键复制审批单、合同、报表等,原型模式可高效实现。
  • 游戏引擎批量生成怪物、NPC、道具等,原型模式提升性能。
  • 云平台环境模板、配置模板的快速克隆。

3. 优缺点分析

3.1 优点

  1. 性能优化:减少重复创建开销,提升系统响应速度。
  2. 简化扩展:无需大量子类,支持动态扩展和运行时配置。
  3. 灵活性高:可动态注册、批量复制,适应多变需求。

3.2 缺点

  1. 深拷贝复杂:对象关系复杂时,深拷贝实现难度大。
  2. 克隆限制:如不可变对象、资源句柄等难以克隆。
  3. 维护成本:需保证克隆对象状态一致性,易出错。

4. 实际应用案例

  1. 文档/模板复制:如Word、PPT、设计稿等模板批量生成。
  2. 游戏开发:如角色、道具、场景等对象池批量克隆。
  3. 缓存/对象池:如数据库连接、线程、任务等对象池管理。
  4. 配置/环境克隆:如系统配置、环境参数的快速复制。

5. 结构与UML类图

@startuml
package "Prototype Pattern" #DDDDDD {interface Prototype {+ clone(): Prototype}class ConcretePrototype implements Prototype {- field: String+ clone(): Prototype}class PrototypeRegistry {+ addPrototype(key: String, prototype: Prototype): void+ getPrototype(key: String): Prototype- prototypes: Map<String, Prototype>}Prototype <|.. ConcretePrototypePrototypeRegistry o-- Prototype : prototypes
}
@enduml

6. 代码示例

6.1 基本结构示例

业务背景: 实现原型模式的基本结构,支持对象克隆和注册表管理。

package com.example.patterns.prototype;import java.util.HashMap;
import java.util.Map;
import java.util.Objects;// 原型接口,定义克隆方法
public interface Prototype {/*** 克隆当前对象* @return 克隆后的新对象*/Prototype clone();
}// 具体原型实现,支持基本属性克隆
public class ConcretePrototype implements Prototype {private String field;private int value;public ConcretePrototype(String field, int value) { this.field = field;this.value = value;}// 拷贝构造函数,用于克隆private ConcretePrototype(ConcretePrototype other) {this.field = other.field;this.value = other.value;}@Overridepublic Prototype clone() { return new ConcretePrototype(this); }// Getter和Setter方法public String getField() { return field; }public void setField(String field) { this.field = field; }public int getValue() { return value; }public void setValue(int value) { this.value = value; }@Overridepublic String toString() {return "ConcretePrototype{field='" + field + "', value=" + value + "}";}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;ConcretePrototype that = (ConcretePrototype) o;return value == that.value && Objects.equals(field, that.field);}@Overridepublic int hashCode() {return Objects.hash(field, value);}
}// 原型注册表,管理原型对象
public class PrototypeRegistry {private static final Map<String, Prototype> prototypes = new HashMap<>();/*** 注册原型对象*/public static void addPrototype(String key, Prototype prototype) {if (key == null || prototype == null) {throw new IllegalArgumentException("Key and prototype cannot be null");}prototypes.put(key, prototype);}/*** 获取原型的克隆对象*/public static Prototype getPrototype(String key) {Prototype prototype = prototypes.get(key);if (prototype == null) {throw new IllegalArgumentException("Prototype not found for key: " + key);}return prototype.clone();}/*** 移除原型*/public static void removePrototype(String key) {prototypes.remove(key);}/*** 清空所有原型*/public static void clear() {prototypes.clear();}
}

6.2 深拷贝实现示例

业务背景: 实现包含复杂对象的深拷贝,避免引用共享问题。

// 复杂对象示例:员工信息包含地址对象
public class Address implements Cloneable {private String city;private String street;private String zipCode;public Address(String city, String street, String zipCode) {this.city = city;this.street = street;this.zipCode = zipCode;}// 深拷贝实现@Overridepublic Address clone() {try {return (Address) super.clone();} catch (CloneNotSupportedException e) {// 这种情况不应该发生,因为我们实现了Cloneablethrow new RuntimeException("Clone not supported", e);}}// Getter和Setter方法public String getCity() { return city; }public void setCity(String city) { this.city = city; }public String getStreet() { return street; }public void setStreet(String street) { this.street = street; }public String getZipCode() { return zipCode; }public void setZipCode(String zipCode) { this.zipCode = zipCode; }@Overridepublic String toString() {return "Address{city='" + city + "', street='" + street + "', zipCode='" + zipCode + "'}";}
}// 员工原型,包含复杂对象引用
public class Employee implements Prototype {private String name;private String department;private Address address;private List<String> skills;public Employee(String name, String department, Address address) {this.name = name;this.department = department;this.address = address;this.skills = new ArrayList<>();}// 深拷贝构造函数private Employee(Employee other) {this.name = other.name;this.department = other.department;// 深拷贝地址对象this.address = other.address != null ? other.address.clone() : null;// 深拷贝技能列表this.skills = new ArrayList<>(other.skills);}@Overridepublic Prototype clone() {return new Employee(this);}public void addSkill(String skill) {skills.add(skill);}// Getter和Setter方法public String getName() { return name; }public void setName(String name) { this.name = name; }public String getDepartment() { return department; }public void setDepartment(String department) { this.department = department; }public Address getAddress() { return address; }public void setAddress(Address address) { this.address = address; }public List<String> getSkills() { return skills; }@Overridepublic String toString() {return "Employee{name='" + name + "', department='" + department + "', address=" + address + ", skills=" + skills + "}";}
}

6.3 序列化克隆实现

业务背景: 使用序列化方式实现深拷贝,适用于复杂对象图。

import java.io.*;// 支持序列化克隆的基类
public abstract class SerializablePrototype implements Prototype, Serializable {private static final long serialVersionUID = 1L;@Overridepublic Prototype clone() {try {// 使用序列化进行深拷贝ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);oos.close();ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);Prototype cloned = (Prototype) ois.readObject();ois.close();return cloned;} catch (IOException | ClassNotFoundException e) {throw new RuntimeException("Serialization clone failed", e);}}
}// 使用序列化克隆的配置对象
public class Configuration extends SerializablePrototype {private String environment;private Map<String, String> properties;private List<String> servers;public Configuration(String environment) {this.environment = environment;this.properties = new HashMap<>();this.servers = new ArrayList<>();}public void addProperty(String key, String value) {properties.put(key, value);}public void addServer(String server) {servers.add(server);}// Getter方法public String getEnvironment() { return environment; }public Map<String, String> getProperties() { return properties; }public List<String> getServers() { return servers; }@Overridepublic String toString() {return "Configuration{environment='" + environment + "', properties=" + properties + ", servers=" + servers + "}";}
}

6.4 实际业务场景:文档模板系统

业务背景: 实现文档模板系统,支持快速复制和定制不同类型的文档。

// 文档接口
public interface Document extends Prototype {void setTitle(String title);void setContent(String content);String getTitle();String getContent();
}// 报告文档原型
public class ReportDocument implements Document {private String title;private String content;private String author;private Date createDate;private List<String> sections;public ReportDocument() {this.createDate = new Date();this.sections = new ArrayList<>();// 预设报告模板结构this.sections.add("摘要");this.sections.add("背景");this.sections.add("分析");this.sections.add("结论");}// 拷贝构造函数private ReportDocument(ReportDocument other) {this.title = other.title;this.content = other.content;this.author = other.author;this.createDate = new Date(); // 新文档使用当前时间this.sections = new ArrayList<>(other.sections);}@Overridepublic Prototype clone() {return new ReportDocument(this);}@Overridepublic void setTitle(String title) { this.title = title; }@Overridepublic void setContent(String content) { this.content = content; }@Overridepublic String getTitle() { return title; }@Overridepublic String getContent() { return content; }public void setAuthor(String author) { this.author = author; }public String getAuthor() { return author; }public List<String> getSections() { return sections; }@Overridepublic String toString() {return "ReportDocument{title='" + title + "', author='" + author + "', sections=" + sections.size() + ", createDate=" + createDate + "}";}
}// 合同文档原型
public class ContractDocument implements Document {private String title;private String content;private String partyA;private String partyB;private Date effectiveDate;private BigDecimal amount;public ContractDocument() {this.effectiveDate = new Date();this.amount = BigDecimal.ZERO;}private ContractDocument(ContractDocument other) {this.title = other.title;this.content = other.content;this.partyA = other.partyA;this.partyB = other.partyB;this.effectiveDate = new Date(); // 新合同使用当前日期this.amount = other.amount;}@Overridepublic Prototype clone() {return new ContractDocument(this);}@Overridepublic void setTitle(String title) { this.title = title; }@Overridepublic void setContent(String content) { this.content = content; }@Overridepublic String getTitle() { return title; }@Overridepublic String getContent() { return content; }// 合同特有方法public void setPartyA(String partyA) { this.partyA = partyA; }public void setPartyB(String partyB) { this.partyB = partyB; }public void setAmount(BigDecimal amount) { this.amount = amount; }@Overridepublic String toString() {return "ContractDocument{title='" + title + "', partyA='" + partyA + "', partyB='" + partyB + "', amount=" + amount + "}";}
}// 文档管理器
public class DocumentManager {private static final PrototypeRegistry registry = new PrototypeRegistry();static {// 初始化文档模板ReportDocument reportTemplate = new ReportDocument();reportTemplate.setTitle("月度报告模板");reportTemplate.setAuthor("系统管理员");ContractDocument contractTemplate = new ContractDocument();contractTemplate.setTitle("标准合同模板");contractTemplate.setPartyA("甲方公司");registry.addPrototype("report", reportTemplate);registry.addPrototype("contract", contractTemplate);}public static Document createDocument(String type, String title) {Document doc = (Document) registry.getPrototype(type);doc.setTitle(title);return doc;}
}// 客户端使用示例
public class DocumentClient {public static void main(String[] args) {// 创建报告文档Document report1 = DocumentManager.createDocument("report", "Q1财务报告");report1.setContent("第一季度财务分析内容...");Document report2 = DocumentManager.createDocument("report", "Q2财务报告");report2.setContent("第二季度财务分析内容...");// 创建合同文档Document contract1 = DocumentManager.createDocument("contract", "软件开发合同");contract1.setContent("软件开发合同条款...");System.out.println("Report 1: " + report1);System.out.println("Report 2: " + report2);System.out.println("Contract: " + contract1);}// 总结:通过原型模式,文档系统可快速创建各种类型文档,提升效率和一致性。
}## 7. 测试用例**业务背景:** 验证原型模式的核心功能,包括基本克隆、深拷贝和注册表管理。```java
import org.junit.Test;
import static org.junit.Assert.*;public class PrototypePatternTest {@Testpublic void testBasicClone() {// 测试基本克隆功能ConcretePrototype original = new ConcretePrototype("test", 42);ConcretePrototype cloned = (ConcretePrototype) original.clone();// 验证克隆对象与原对象不是同一个实例assertNotSame(original, cloned);// 验证克隆对象的内容相同assertEquals(original.getField(), cloned.getField());assertEquals(original.getValue(), cloned.getValue());assertEquals(original, cloned);}@Testpublic void testPrototypeRegistry() {// 清空注册表PrototypeRegistry.clear();// 注册原型ConcretePrototype prototype = new ConcretePrototype("template", 100);PrototypeRegistry.addPrototype("test", prototype);// 获取克隆对象Prototype cloned = PrototypeRegistry.getPrototype("test");ConcretePrototype clonedConcrete = (ConcretePrototype) cloned;assertEquals("template", clonedConcrete.getField());assertEquals(100, clonedConcrete.getValue());assertNotSame(prototype, cloned);}@Testpublic void testDeepCopy() {// 测试深拷贝Address address = new Address("北京", "中关村大街", "100080");Employee original = new Employee("张三", "技术部", address);original.addSkill("Java");original.addSkill("Spring");Employee cloned = (Employee) original.clone();// 验证深拷贝:修改克隆对象的地址不影响原对象cloned.getAddress().setCity("上海");cloned.addSkill("Python");assertEquals("北京", original.getAddress().getCity());assertEquals("上海", cloned.getAddress().getCity());assertEquals(2, original.getSkills().size());assertEquals(3, cloned.getSkills().size());}@Testpublic void testDocumentSystem() {// 测试文档模板系统Document report1 = DocumentManager.createDocument("report", "Q1报告");Document report2 = DocumentManager.createDocument("report", "Q2报告");// 验证不同的文档实例assertNotSame(report1, report2);assertEquals("Q1报告", report1.getTitle());assertEquals("Q2报告", report2.getTitle());// 验证报告文档的特定属性assertTrue(report1 instanceof ReportDocument);assertTrue(report2 instanceof ReportDocument);}@Testpublic void testRegistryExceptionHandling() {// 测试注册表异常处理assertThrows(IllegalArgumentException.class, () -> {PrototypeRegistry.addPrototype(null, new ConcretePrototype("test", 1));});assertThrows(IllegalArgumentException.class, () -> {PrototypeRegistry.addPrototype("test", null);});assertThrows(IllegalArgumentException.class, () -> {PrototypeRegistry.getPrototype("nonexistent");});}
}

8. 常见误区与反例

8.1 常见误区

  • 误区1 :浅拷贝导致引用共享

    // 错误示例:简单的字段复制导致引用共享
    public class BadEmployee implements Prototype {private Address address;public Prototype clone() {BadEmployee clone = new BadEmployee();clone.address = this.address; // 浅拷贝,共享引用return clone;}
    }
    

    正确做法:实现深拷贝,确保引用对象也被克隆。

  • 误区2 :原型注册表未做防护

    // 错误示例:直接返回原型对象
    public static Prototype getPrototype(String key) {return prototypes.get(key); // 返回原始对象,可能被修改
    }
    

    正确做法:始终返回克隆对象,保护原型不被修改。

  • 误区3 :忽略克隆中的资源管理

    // 错误示例:资源句柄直接克隆
    public class BadResource implements Prototype {private FileInputStream inputStream;public Prototype clone() {BadResource clone = new BadResource();clone.inputStream = this.inputStream; // 资源不能共享return clone;}
    }
    

8.2 反例分析

  • 反例1 :不可变对象使用原型模式
    对于StringInteger等不可变对象,使用原型模式没有意义,应直接重用。

  • 反例2 :系统资源句柄克隆
    文件句柄、网络连接、数据库连接等系统资源不能简单克隆,需要重新创建。

  • 反例3 :过度使用原型模式
    对于简单对象,直接使用构造函数创建更简单高效,不需要原型模式。

9. 最佳实践

9.1 设计原则

  1. 深拷贝实现 :优先实现深拷贝,避免引用共享问题

    // 推荐:使用拷贝构造函数
    private Employee(Employee other) {this.name = other.name;this.address = other.address != null ? other.address.clone() : null;this.skills = new ArrayList<>(other.skills);
    }
    
  2. 注册表防护 :注册表应返回克隆对象,保护原型安全

    // 推荐:防护性克隆
    public static Prototype getPrototype(String key) {Prototype prototype = prototypes.get(key);return prototype != null ? prototype.clone() : null;
    }
    
  3. 异常与资源管理 :妥善处理克隆过程中的异常和资源

    // 推荐:完善的异常处理
    @Override
    public Prototype clone() {try {MyClass cloned = (MyClass) super.clone();cloned.resource = createNewResource(); // 重新创建资源return cloned;} catch (CloneNotSupportedException e) {throw new RuntimeException("Clone failed", e);}
    }
    

9.2 性能优化

  1. 克隆策略选择 :根据对象复杂度选择合适的克隆策略

    • 简单对象:拷贝构造函数
    • 复杂对象:序列化克隆
    • 不可变部分:引用复制
  2. 延迟克隆 :对于大对象,考虑写时复制(Copy-on-Write)策略

    // 推荐:写时复制优化
    public class LazyCloneList implements Prototype {private List<String> data;private boolean isCloned = false;private void ensureCloned() {if (!isCloned) {data = new ArrayList<>(data);isCloned = true;}}public void add(String item) {ensureCloned();data.add(item);}
    }
    

9.3 架构设计

  1. 与工厂模式结合 :原型注册表可与工厂模式结合,提供统一的对象创建接口

  2. 线程安全考虑 :在多线程环境下,确保原型注册表和克隆操作的线程安全

    // 推荐:线程安全的注册表
    public class ThreadSafeRegistry {private static final ConcurrentHashMap<String, Prototype> prototypes = new ConcurrentHashMap<>();
    }
    
  3. 版本控制 :为原型对象添加版本信息,支持向后兼容的序列化克隆

10. 参考资料与延伸阅读

  • 《设计模式:可复用面向对象软件的基础》GoF
  • Effective Java(中文版)
  • https://refactoringguru.cn/design-patterns/prototype
  • https://www.baeldung.com/java-prototype-pattern

本文为设计模式系列第8篇,后续每篇将聚焦一个设计模式或设计原则,深入讲解实现与应用,敬请关注。

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

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

相关文章

区块链到底是什么?

区块链本质上是一种去中心化的分布式账本技术&#xff0c;具有以下核心特点&#xff1a; - 去中心化&#xff1a;没有中央管理机构&#xff0c;数据由网络中的多个节点共同维护&#xff0c;比如比特币网络中各个节点都保存着完整账本。 - 分布式存储&#xff1a;数据不是存在一…

系统架构设计师论文分享-论ATAM的使用

我的软考历程 摘要 2023年2月&#xff0c;我司通过了研发纱线MES系统的立项&#xff0c;该系统为国内纱线工厂提供SAAS服务&#xff0c;旨在提高纱线工厂的数字化和智能化水平。我在本项目中担任系统架构设计师&#xff0c;负责整个项目的架构设计工作。本文结合我在该项目中…

vue-28(服务器端渲染(SSR)简介及其优势)

服务器端渲染&#xff08;SSR&#xff09;简介及其优势 服务器端渲染&#xff08;SSR&#xff09;是现代网络应用的关键技术&#xff0c;特别是使用 Vue.js 等框架构建的应用。它通过在服务器上渲染初始应用状态来弥补传统单页应用&#xff08;SPA&#xff09;的局限性&#x…

工业电子 | 什么是SerDes,为何工业和汽车应用需要它?

重点内容速览&#xff1a; 1. 什么是SerDes&#xff1f; 2. ADI&#xff1a;私有协议的GMSL将向公有协议转变 3. TI&#xff1a;工业和汽车有两套SerDes解决方案 4. Microchip&#xff1a;推出通用协议SerDes芯片 5. 罗姆&#xff1a;主要针对汽车领域 6. 国产SerDes芯…

大事件项目记录4-用户接口开发-更新用户基本信息

4&#xff09;更新用户基本信息。 UserController.java&#xff1a; UserMapper.java&#xff1a; Update("update user set nickname #{nickname},email #{email},update_time #{updateTime} where id #{id}")void update(User user); UserServiceInterface…

Transformer结构--输入编码(BPE,PE)

在Transformer结构中&#xff0c;输入编码是模型处理文本数据的关键步骤&#xff0c;其中**BPE&#xff08;Byte Pair Encoding&#xff0c;字节对编码&#xff09;和PE&#xff08;Positional Encoding&#xff0c;位置编码&#xff09;**是两种重要的编码方式&#xff0c;它们…

Confluence-测试用例设计指导方法

测试经验知识库 典型的测试场景验证点各个项目有价值的经验和测试点 测试经验知识库 - 草稿测试用例执行量化指导建议 何时需要进行全量测试和如何定义和执行测试用例量的一些建议和标准 端对端&#xff08;E2E&#xff09;测试用例设计指导方案 在测试行业中&#xff0c;端到端…

浅析JVM

一、JVM运行流程 如图&#xff1a; JVM由四个部分构成&#xff1a; 1.类加载器 加载类文件到内存2.运行时数据区 写的程序需要加载到这里才能运行3.执行引擎 负责解释命令&#xff0c;提交操作系统执行4.本地接口 融合不同编程语言为java所用&#xff0c;如Java程序驱动打印…

多个 Job 并发运行时共享配置文件导致上下文污染,固化 Jenkins Job 上下文

基于 context.py 固化 Jenkins Job 上下文的完整方案&#xff0c;适用于你当前的工作流&#xff08;Python Jenkins Pipeline&#xff09;&#xff0c;解决&#xff1a; 多个 Job 并发运行时共享配置文件导致上下文污染&#xff1b;读取环境变量或 JSON 文件时被其他 Job 修改…

简木易支付系统 功能齐全,对接接口超多

简木易支付系统&#xff0c;作为一款引领行业潮流的卓越支付解决方案&#xff0c;依托先进的 PHP MySQL 技术架构精心打造。在开发过程中&#xff0c;它巧妙运用了功能强大的 ThinkPHP8 框架&#xff0c;完美融合前端主流技术 Vue、Element 以及 Layuiadmin&#xff0c;共同铸…

【软考高项论文】信息系统项目的人力资源管理

摘要 本文围绕信息系统项目的人力资源管理展开论述。以我在2024年参与的为大型国有企业构建供应链管理系统项目为例&#xff0c;阐述了项目人力资源管理的主要流程&#xff0c;包括规划、组建、建设和管理团队四个过程&#xff0c;以及所运用的工具和理论。同时&#xff0c;分…

【EI会议征稿】东北大学主办第三届机器视觉、图像处理与影像技术国际会议(MVIPIT 2025)

一、会议信息 大会官网&#xff1a;www.mvipit.org 官方邮箱&#xff1a;mvipit163.com 会议地点&#xff1a;辽宁沈阳 主办单位&#xff1a;东北大学 会议时间&#xff1a;2025 年 9 月 27 日-9 月 29 日 二、征稿主题 集中但不限于“机器视觉、图像处理与影像技术”等其…

从零开始的云计算生活——第二十三天,稍作休息,Tomcat

目录 一.故事背景 二.Tomcat概述 1、Tomcat介绍 2、Tomcat历史 二、Tomcat原理分析 1、Http工作原理 2、Tomcat整体架构 3、Coyote连接器架构 4、Catalina容器架构 5、Jasper处理流程 6、JSP编译过程 7、Tomcat启动流程 8、Tomcat请求处理流程 三、Tomcat安装与配…

几种基于Doherty结构的GAN氮化镓功放设计方法介绍

功率放大器是现代无线通信系统中最重要的组件之一。理想情况下&#xff0c;它们能够以高线性度和高效率提供高输出功率。但通常在这三个关键的功率放大器性能参数之间需要进行权衡取舍&#xff0c;而且具有最高输出功率和线性度的放大器往往会牺牲效率。 在支持宽带宽和高数据…

前端打印计算单位 cm、mm、px

A4 纵向 宽&#xff1a;21cm&#xff0c;210mm&#xff0c;793.698px 高&#xff1a;29.7cm&#xff0c;297mm&#xff0c;1122.520px A4 横向 宽&#xff1a;29.7cm&#xff0c;297mm&#xff0c;1122.520px 高&#xff1a;21cm&#xff0c;210mm&#xff0c;793.698px …

c# sugersql 获取子表数据排序

在C#中使用Sugar ORM&#xff08;一个流行的.NET ORM框架&#xff09;获取子表数据并进行排序&#xff0c;可以通过以下几种方式实现&#xff1a; 1. 使用HasMany或HasOne配置 首先&#xff0c;确保你在配置实体时已经正确设置了HasMany或HasOne关系。例如&#xff0c;假设你…

【nRF52832】【环境搭建 3】【如何新建一个纯单片机开发的工程】

1. 前言 笨叔&#xff0c;又要开始扯淡了!!! 不感兴趣的同学&#xff0c;可以跳过了!!! 笨叔之前在大学里面&#xff0c; 刚接触单片机时。就被 windows 平台 例如 keill 5 、IAR 等一堆开会环境差点劝退。 当时也是坚持咬牙一点点摸索过来的。刚摸索明白&#xff0c;觉得单片…

Spring-loC与DI

目录 1 loC控制反转思想 2 DI依赖注入 3 loC详解 3.1 存储Bean &#xff08;1&#xff09;Controller &#xff08;2&#xff09;Service &#xff08;3&#xff09;Repository &#xff08;4&#xff09;Component &#xff08;5&#xff09;Configuration &#xf…

职业本科单片机与嵌入式技术实训室建设设想

一、引言 在当今数字化与智能化飞速发展的时代&#xff0c;单片机与嵌入式技术作为信息技术领域的关键支撑&#xff0c;广泛应用于工业控制、智能家居、物联网、汽车电子等众多行业&#xff0c;成为推动产业升级和创新发展的核心驱动力。职业本科教育旨在培养适应生产、建设、…

传统消防演练与 VR 消防演练的区别有哪些

演练形式&#xff1a;传统消防演练往往依托真实的场地&#xff0c;像空旷的广场、废弃的建筑物或是专门的消防训练基地等。参与者能触摸并使用实实在在的消防设备&#xff0c;例如干粉灭火器、二氧化碳灭火器、消防水带等。在演练时&#xff0c;会通过点燃模拟火源、释放烟雾等…