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

Go和Java实现原型模式

Go和Java实现原型模式

下面将通过一个克隆的示例来说明原型模式的使用。

1、原型模式

原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对

象的最佳方式之一。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种

模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它

的克隆,在需要的时候更新数据库,以此来减少数据库调用。

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

  • 主要解决:在运行期建立和删除原型。

  • 何时使用:1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定

    时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只

    能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类

    更方便一些。

  • 如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。

  • 关键代码:1、实现克隆操作,在 JAVA 实现 Cloneable 接口,重写 clone(),在 .NET 中可以使用 Object 类的

    MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔

    离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。

  • 应用实例:1、细胞分裂。 2、JAVA 中的 Object clone() 方法。

  • 优点:1、性能提高。 2、逃避构造函数的约束。

  • 缺点:1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很

    容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable

    接口。

  • 使用场景:1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、

    性能和安全要求的场景。 4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型

    模式。 5、一个对象多个修改者的场景。 6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要

    修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 7、在实际项目中,原型模式很少单独出

    现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型

    模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

  • 注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象

    的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。

  • 适用性:

    当一个系统应该独立于它的产品创建、构成和表示时。

    当要实例化的类是在运行时刻指定时,例如通过动态装载。

    为了避免创建一个与产品类层次平行的工厂层次时。

    当一个类的实例只能有几个不同状态组合中的一种时。

    建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

2、Go实现原型模式

package prototype// ========== Cloneable ==========
// Cloneable是原型对象需要实现的接口
type Cloneable interface {Clone() Cloneable
}
package prototypeimport "encoding/json"// ========== DeepCopy ==========
// 深拷贝实现Cloneable
type DeepCopy struct {Name string
}// clone也可以使用序列化与反序列化的方式实现深拷贝
func (t *DeepCopy) SerializableClone() Cloneable {var cloneable Cloneableb, _ := json.Marshal(t)json.Unmarshal(b, &cloneable)return cloneable
}func (t *DeepCopy) Clone() Cloneable {tc := *treturn &tc
}
package prototype// ========== ShallowCopy ==========
// 浅拷贝实现Cloneable
type ShallowCopy struct {Name string
}func (t *ShallowCopy) Clone() Cloneable {return t
}
package prototype// ========== PrototypeManager ==========
type PrototypeManager struct {prototypes map[string]Cloneable
}func NewPrototypeManager() *PrototypeManager {return &PrototypeManager{prototypes: make(map[string]Cloneable),}
}func (p *PrototypeManager) Get(name string) Cloneable {return p.prototypes[name].Clone()
}func (p *PrototypeManager) Set(name string, prototype Cloneable) {p.prototypes[name] = prototype
}
package mainimport ("fmt". "proj/prototype"
)var (deepCopyManager    *PrototypeManagershallowCopyManager *PrototypeManager
)func init() {deepCopyManager = NewPrototypeManager()deepCopyManager.Set("dc", &DeepCopy{Name: "DeepCopy"})shallowCopyManager = NewPrototypeManager()shallowCopyManager.Set("sc", &ShallowCopy{Name: "ShallowCopy"})
}func main() {// ========== TestDeepCopyClone ==========t1 := deepCopyManager.Get("dc")t2 := t1.Clone()// 深拷贝,指向的不是同一个变量的地址// falsefmt.Println(t1 == t2)t3 := t2.(*DeepCopy)t3.Name = "DeepCopyUpdate"t4 := t1.(*DeepCopy)// 深拷贝Name,不会影响到copy前的变量// DeepCopyUpdatefmt.Println(t3.Name)// DeepCopyfmt.Println(t4.Name)// ========== TestShallowCopyClone ==========t5 := shallowCopyManager.Get("sc")t6 := t5.Clone()// 浅拷贝,变量地址的指向不变// truefmt.Println(t5 == t6)t7 := t6.(*ShallowCopy)t7.Name = "ShallowCopyUpdate"t8 := t5.(*ShallowCopy)// 浅拷贝Name,copy之前的变量和copy之后的变量同时更改// ShallowCopyUpdatefmt.Println(t7.Name)// ShallowCopyUpdatefmt.Println(t8.Name)
}

3、Java实现原型模式

创建一个抽象类 Shape 和扩展了 Shape 类的实体类,然后定义类 ShapeCache,该类把 shape 对象存储在一个

Hashtable 中,并在请求的时候返回它们的克隆。

package com.prototype;// ========== Shape ==========
public abstract class Shape implements Cloneable {private String id;protected String type;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getType() {return type;}public void setType(String type) {this.type = type;}abstract void draw();@Overridepublic Object clone() {Object clone = null;try {clone = super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return clone;}
}
package com.prototype;// ========== Circle ==========
public class Circle extends Shape {public Circle(){type = "Circle";}@Overridepublic void draw() {System.out.println("Draw Circle!");}
}
package com.prototype;// ========== Rectangle ==========
public class Rectangle extends Shape {public Rectangle(){type = "Rectangle";}@Overridepublic void draw() {System.out.println("Draw Rectangle!");}
}
package com.prototype;// ========== Square ==========
public class Square extends Shape {public Square(){type = "Square";}@Overridepublic void draw() {System.out.println("Draw Square!");}
}
package com.prototype;import java.util.Hashtable;// ========== ShapeCache ==========
public class ShapeCache {private final static Hashtable<String, Shape> SHAPE_MAP = new Hashtable<>();public static Shape getShape(String shapeId) {Shape cachedShape = SHAPE_MAP.get(shapeId);// 这里是浅拷贝,返回一个新的对象// 新对象里的引用类型变量地址指向的还是原对象内引用类型地址return (Shape) cachedShape.clone();}// 对每种形状都运行数据库查询,并创建该形状public static void loadCache() {Circle circle = new Circle();circle.setId("1");SHAPE_MAP.put(circle.getId(),circle);Square square = new Square();square.setId("2");SHAPE_MAP.put(square.getId(),square);Rectangle rectangle = new Rectangle();rectangle.setId("3");SHAPE_MAP.put(rectangle.getId(),rectangle);}
}
package com.prototype;public class Test {public static void main(String[] args) {ShapeCache.loadCache();Shape clonedShape = ShapeCache.getShape("1");System.out.println("Shape : " + clonedShape.getType());clonedShape.draw();Shape clonedShape2 = ShapeCache.getShape("2");System.out.println("Shape : " + clonedShape2.getType());clonedShape.draw();Shape clonedShape3 = ShapeCache.getShape("3");System.out.println("Shape : " + clonedShape3.getType());clonedShape3.draw();}
}
# 输出
Shape : Circle
Draw Circle!
Shape : Square
Draw Circle!
Shape : Rectangle
Draw Rectangle!

4、深拷贝和浅拷贝的区别

深拷贝和浅拷贝是指在复制一个对象时,复制的方式不同。

在进行深拷贝时,复制的是对象及其内部的所有对象。这意味着,如果原始对象中包含一个列表,那么在深拷贝

后,原始对象和拷贝对象中的列表是两个独立的对象,即使它们看起来完全相同,也不会相互影响。

相反,浅拷贝仅复制对象本身,但是如果对象内部包含其他对象,则这些对象并不会被复制。因此,如果原始对象

中包含一个列表,那么在浅拷贝后,原始对象和拷贝对象中的列表是同一个对象。如果你在拷贝对象中更改了列

表,那么原始对象中的列表也会发生变化。

总:

复制对象后,如果修改了原对象或新对象的数据,造成了对其他对象的数据也同时发生了变化的现象,就是浅拷

贝,对象之间仍然存在关联。

如果复制后的对象与原对象,无论数据如何变化,都不会对其它对象带来变化,就是深拷贝,对象之间已经毫无关

系。

5、补充Java的深拷贝和浅拷贝的实现

5.1 浅拷贝

package com.shallowcopy;// ========== ShallowCopyDemo ==========
public class ShallowCopyDemo {public static void main(String[] args) {// ======浅拷贝=============System.out.println("======浅拷贝=============");// 初始化对象User user = new User();user.setAge(25);Name name = new Name();name.setFirst("li");name.setSecond("si");user.setName(name);// 实现对象克隆User cloneUser = (User) user.clone();// 修改原始对象属性值cloneUser.setAge(27);cloneUser.getName().setFirst("wang");cloneUser.getName().setSecond("wu");// 源对象:User{age=25, name=Name{first='wang', second='wu'}}System.out.println("源对象:" + user);// 新对象:User{age=27, name=Name{first='wang', second='wu'}}System.out.println("新对象:" + cloneUser);// 在clone()方法中,我们仅对User对象实现了克隆,但是没有对User类下的属性类Name进行克隆// 执行克隆后,新User对象下的Name属性与原对象下的Name属性,仍然指向同一块内存// 如果Name属性发生变更,所有克隆对象的Name属性都会变化,此即为浅克隆}
}class User implements Cloneable{int age;Name name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Name getName() {return name;}public void setName(Name name) {this.name = name;}@Overridepublic String toString() {return "User{" +"age=" + age +", name=" + name +'}';}// 实现Cloneable接口并重写Object类的clone()方法@Overridepublic Object clone() {try {return super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}
}class Name{String first;String second;public String getFirst() {return first;}public void setFirst(String first) {this.first = first;}public String getSecond() {return second;}public void setSecond(String second) {this.second = second;}@Overridepublic String toString() {return "Name{" +"first='" + first + '\'' +", second='" + second + '\'' +'}';}
}

5.2 深拷贝

package com.deepcopy;// ========== DeepCopyDemo ==========
public class DeepCopyDemo {public static void main(String[] args) {// ======深拷贝=============System.out.println("======深拷贝=============");// 初始化对象User user = new User();user.setAge(25);Name name = new Name();name.setFirst("li");name.setSecond("si");user.setName(name);// 实现对象克隆User cloneUser = (User) user.clone();// 修改原始对象属性值cloneUser.setAge(27);cloneUser.getName().setFirst("wang");cloneUser.getName().setSecond("wu");// 源对象:User{age=25, name=Name{first='li', second='si'}}System.out.println("源对象:" + user);// 新对象:User{age=27, name=Name{first='wang', second='wu'}}System.out.println("新对象:" + cloneUser);}
}class Name implements Cloneable{String first;String second;public String getFirst() {return first;}public void setFirst(String first) {this.first = first;}public String getSecond() {return second;}public void setSecond(String second) {this.second = second;}@Overridepublic String toString() {return "Name{" +"first='" + first + '\'' +", second='" + second + '\'' +'}';}// 实现Cloneable接口并重写Object类的clone()方法@Overridepublic Object clone() {try {return super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}
}class User implements Cloneable{int age;Name name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Name getName() {return name;}public void setName(Name name) {this.name = name;}@Overridepublic String toString() {return "User{" +"age=" + age +", name=" + name +'}';}// 实现Cloneable接口并重写Object类的clone()方法// 这种方法实现的深克隆比较笨重,如果User类下有多个属性类时,要实现深克隆就需要对所有类重写clone()方法@Overridepublic Object clone() {try {User u = (User) super.clone();//调用属性的克隆方法u.setName((Name) this.name.clone());return u;} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}
}

5.3 fastjson实现深拷贝

package com.fastjsondeepcopy;import com.alibaba.fastjson.JSON;public class FastjsonDemo {public static void main(String[] args) {// ======深拷贝=============System.out.println("======深拷贝=============");// 初始化对象User user = new User();user.setAge(25);Name name = new Name();name.setFirst("li");name.setSecond("si");user.setName(name);// 实现对象克隆String jsonString = JSON.toJSONString(user);User cloneUser = JSON.parseObject(jsonString, User.class);// 修改原始对象属性值cloneUser.setAge(27);cloneUser.getName().setFirst("wang");cloneUser.getName().setSecond("wu");// 源对象:User{age=25, name=Name{first='li', second='si'}}System.out.println("源对象:" + user);// 新对象:User{age=27, name=Name{first='wang', second='wu'}}System.out.println("新对象:" + cloneUser);}
}class User{int age;Name name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Name getName() {return name;}public void setName(Name name) {this.name = name;}@Overridepublic String toString() {return "User{" +"age=" + age +", name=" + name +'}';}
}class Name{String first;String second;public String getFirst() {return first;}public void setFirst(String first) {this.first = first;}public String getSecond() {return second;}public void setSecond(String second) {this.second = second;}@Overridepublic String toString() {return "Name{" +"first='" + first + '\'' +", second='" + second + '\'' +'}';}
}

相关文章:

Go和Java实现原型模式

Go和Java实现原型模式 下面将通过一个克隆的示例来说明原型模式的使用。 1、原型模式 原型模式是用于创建重复的对象&#xff0c;同时又能保证性能。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对 象的最佳方式之一。 这种模式是实现了一个原型接口&am…...

linux I/O性能优化

Linux 文件系统 磁盘和文件系统的关系&#xff1a; 磁盘为系统提供了最基本的持久化存储。 文件系统则在磁盘的基础上&#xff0c;提供了一个用来管理文件的树状结构。 文件系统工作原理 索引节点和目录项 文件系统&#xff0c;本身是对存储设备上的文件&#xff0c;进行组织…...

PHP最简单自定义自己的框架model使用(七)

1、实现model使用效果 2、自动加载model,KJ.php //自动加载文件public static function _autoload($className){switch ($className){//自动model类case substr($className,-5)Model:$path MODEL./.$className..php;if(is_file($path)) include $path;break;//自动加载控制器…...

程序猿成长之路之密码学篇-分组密码加密模式及IV(偏移量)的详解

Cipher.getInstance("AES/ECB/PKCS5Padding"); Cipher cipher Cipher.getInstance("AES/CBC/PKCS5Padding"); 在进行加解密编程的时候应该有很多小伙伴接触过以上的语句&#xff0c;但是大伙儿在编码过程中是否了解过ECB/CBC的含义、区别以及PKCS5Padding…...

Windows下批处理删除文件

最近我使用Maven的时候会出现下载jar包不成功的现象&#xff0c;然后需要把它删除然后重新下载&#xff0c;但是有时候文件过多&#xff0c;一个个删除太花费时间&#xff0c;所以用bat的批处理会很舒服。 bat的语法我之前没遇到过&#xff0c;然后我是边学习边试验&#xff0…...

html中文件上传储存到本地路径

第一步:写html文件 <form action"/uplode" method"post" enctype"multipart/form-data">姓名:<input type"text" name"username"><br>年龄:<input type"text" name"age"><…...

第九章 SpringBoot 自动配置原理 入门

1. 引导加载自动配置类 SpringBootApplication -- SpringBootConfiguration -- EnableAutoConfiguration -- ComponentScan //SpringBootApplicationSpringBootConfiguration EnableAutoConfiguration ComponentScan(excludeFilters { Filter(type FilterType.CUSTOM, cl…...

String str=new String(“tango“) 创建了几个对象?

面试回答 创建的对象数 应该是1个或者2个。 首先要清楚什么是对象&#xff1f; Java 是一种面向对象的语言&#xff0c;而 Java 对象在 JVM 中的存储也是有一定的结构的&#xff0c;在 HotSpot 虚拟机中&#xff0c;存储的形式就是 oop-klass model&#xff0c;即 Java 对象模型…...

引入三阶失真的非线性放大器的模拟输出及使用中值滤波器去除峰值研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

【观察者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

简介 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型模式。它定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。 观察者模式使用三个类Subject、Observer和Client。Subject…...

精细解析中文公司名称:智能分词工具助力地名、品牌名、行业词和后缀提取

精细解析中文公司名称&#xff1a;智能分词工具助力地名、品牌名、行业词和后缀提取 中文公司名称分词工具&#xff0c;支持公司名称中的地名&#xff0c;品牌名&#xff08;主词&#xff09;&#xff0c;行业词&#xff0c;公司名后缀提取。 对公司名文本解析&#xff0c;识…...

网络编程(JavaEE初阶系列10)

目录 前言&#xff1a; 1.网络编程的基础 1.1为什么需要网络编程 1.2什么是网络编程 1.3网络编程中的基本概念 1.3.1发送端和接收端 1.3.2请求和响应 1.3.3客户端和服务端 2.Socket套接字 2.1概念 2.2分类 3.UDP数据报套接字编程 3.1DataGramSocket API 3.2Datagr…...

Git常用的指令

Git常用的指令 OMMP提交代码的流程 0、配置&#xff1a; git config --list 查看当前配置 git congig --global user.name user 这个会显示你的提交到git的名字 格式&#xff1a;git config [–local|–global|–system] –unset section.key 格式&#xff1a;git config [–l…...

LoadRunner(2)

一、Controller 1.1场景设计 1.通过VUG打开 施压机器&#xff1a;发起请求的角色(用户本地电脑) 被压机器&#xff1a;处理请求的角色(服务器) 2.直接双击Controller 场景设计&#xff1a;需要关注三个部分 第一部分&#xff1a; 第二部分&#xff1a; 2.1运行场景…...

CTF之逆向之阿里巴巴

题目地址&#xff1a;http://www.shiyanbar.com/ctf/13 题目预览&#xff1a; 解题过程&#xff1a; 1、下载附件发现是exe文件 2、使用PEid和Detect It Easy查壳 和 开发语言&#xff0c;发现没有加壳&#xff0c;都是用C#开发的 3、C#和Java Python属于解释型语言&#xff…...

Labview控制APx(Audio Precision)进行测试测量(五)

驱动程序 VIs如何处理配置设置中的单元 APx500 应用程序具有复杂的控件&#xff0c;具有以下功能: 数值和单位组合在一个控制中(例如&#xff0c;1.000 Vrms ) •值转换为 SI 格式(例如&#xff0c;1.000 mVrms 或 1.000 μVrms) •单位之间的转换发生在控制(例如&#xff0c;V…...

在单元测试中使用Jest模拟VS Code extension API

对VS Code extension进行单元测试时通常会遇到一个问题&#xff0c;代码中所使用的VS Code编辑器的功能都依赖于vscode库&#xff0c;但是我们在单元测试中并没有添加对vscode库的依赖&#xff0c;所以导致运行单元测试时出错。由于vscode库是作为第三方依赖被引入到我们的VS C…...

django boostrap html实现可拖拽的左右布局,鼠标拖动调整左右布局的大小或占比

一、实现的效果 最近需要在Django项目中,实现一个左右布局的html页面,页面框架使用的是boostrap。但这个布局不是简单的左右分栏布局,而是需要实现可以通过鼠标拖拽的方式动态调整左右两侧布局的大小和占比。效果大致如下: 一开始,页面分为左右两块布局: 鼠标放到中间的…...

谈谈闭包和闭包使用场景

一、什么是闭包 概念&#xff1a;闭包还是作用域的一种特殊应用 二、触发闭包的情况 1.函数当做返回值被返回 2.函数当做参数被传递 3.自执行匿名函数 //情况1&#xff1a;函数当做返回值被返回 function fn(){const a 1;return function(){console.log(a) //1}; } const a …...

MATLAB算法实战应用案例精讲-【图像处理】边界框锚框

目录 目标检测 应用场景 目标检测发展历程 常用数据集 边界框(bounding box)...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

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

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

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

elementUI点击浏览table所选行数据查看文档

项目场景&#xff1a; table按照要求特定的数据变成按钮可以点击 解决方案&#xff1a; <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...