零基础设计模式——第二部分:创建型模式 - 原型模式

news2025/5/24 9:19:44

第二部分:创建型模式 - 5. 原型模式 (Prototype Pattern)

我们已经探讨了单例、工厂方法、抽象工厂和生成器模式。现在,我们来看创建型模式的最后一个主要成员——原型模式。这种模式关注的是通过复制现有对象来创建新对象,而不是通过传统的构造函数实例化。

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

原型模式 (Prototype Pattern)

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

想象一下细胞分裂:一个细胞(原型)可以通过分裂(克隆)产生一个新的、与自身几乎完全相同的细胞。或者,在绘图软件中,你画了一个复杂的图形(原型),然后可以通过“复制”和“粘贴”操作快速创建多个相同的图形副本,再对副本进行微调。

原型模式的核心就是“克隆”或“复制”。当创建一个对象的成本很高(例如,需要复杂的计算、数据库查询或网络请求)时,如果已经有一个相似的对象存在,通过复制这个现有对象来创建新对象可能会更高效。

1. 目的 (Intent)

原型模式的主要目的:

  1. 提高性能:当创建新对象的成本较大时(如初始化时间长、资源消耗多),通过复制已有的原型实例来创建新对象,可以避免重复执行这些昂贵的初始化操作。
  2. 简化对象创建:如果一个对象的创建过程比较复杂,或者需要依赖某些运行时的状态,通过克隆一个已配置好的原型对象可以简化新对象的创建。
  3. 动态添加或删除产品:可以在运行时通过注册原型实例来动态地增加或删除系统中可用的产品类型,而无需修改工厂类(如果与工厂模式结合使用)。
  4. 避免与产品具体类耦合:客户端可以只知道抽象的原型接口,通过克隆来获取新对象,而无需知道具体的实现类名。

2. 生活中的例子 (Real-world Analogy)

  • 复印文件

    • 原型 (Prototype):原始文件(比如一份合同模板)。
    • 克隆操作 (Clone):复印机复印的过程。
    • 新对象 (Cloned Object):复印出来的文件副本。
      你不需要重新打字排版来得到一份新的合同,只需要复印原件,然后在副本上修改少量信息(如签约方、日期)即可。
  • 生物克隆:如克隆羊多莉。多莉就是通过复制现有羊的细胞(原型)而创建的。

  • 制作模具和铸件

    • 原型:一个精心制作的模具。
    • 克隆操作:使用模具进行浇筑。
    • 新对象:通过模具生产出来的多个相同铸件。
  • 游戏中的敌人复制:在一个游戏中,当需要生成大量相同类型的敌人时,可以先创建一个敌人对象作为原型,并设置好其初始属性(如生命值、攻击力、模型等)。之后需要新的敌人时,直接克隆这个原型,而不是每次都从头加载资源和设置属性。

3. 结构 (Structure)

原型模式的结构相对简单,通常包含以下角色:

  1. Prototype (抽象原型):声明一个克隆自身的接口(通常是一个 clone() 方法)。
  2. ConcretePrototype (具体原型):实现 Prototype 接口,重写 clone() 方法来复制自身。这个类是实际被复制的对象。
  3. Client (客户端):让一个原型克隆自身从而创建一个新的对象。客户端不需要知道具体的原型类名,只需要通过抽象原型接口来操作。
    在这里插入图片描述
    克隆过程
  4. 客户端持有一个抽象原型对象的引用。
  5. 当客户端需要一个新的对象时,它调用原型对象的 clone() 方法。
  6. 具体原型类实现 clone() 方法,创建一个当前对象的副本并返回。
  7. 客户端得到一个新的对象,这个新对象与原型对象具有相同的初始状态(属性值)。

4. 深拷贝 vs. 浅拷贝 (Deep Copy vs. Shallow Copy)

这是原型模式中一个非常重要的概念。

  • 浅拷贝 (Shallow Copy)

    • 当复制一个对象时,只复制对象本身和其中的基本数据类型成员的值。
    • 如果对象包含对其他对象的引用(引用类型成员),则只复制这些引用,而不复制引用所指向的对象。因此,原对象和副本中的引用类型成员将指向内存中的同一个对象。
    • 修改副本中的引用类型成员所指向的对象,会影响到原对象中对应的成员(因为它们指向同一个东西)。
  • 深拷贝 (Deep Copy)

    • 当复制一个对象时,不仅复制对象本身和基本数据类型成员,还会递归地复制所有引用类型成员所指向的对象。
    • 原对象和副本中的引用类型成员将指向不同的、内容相同的对象。
    • 修改副本中的引用类型成员所指向的对象,不会影响到原对象。

选择深拷贝还是浅拷贝取决于具体需求。如果希望副本的修改不影响原型,或者原型和副本需要独立地管理其引用的对象,那么应该使用深拷贝。如果共享引用的对象是不可变的,或者业务逻辑允许共享,那么浅拷贝可能就足够了,并且性能通常更高。

在Java中,Object类的 clone() 方法默认执行的是浅拷贝。要实现深拷贝,需要在 clone() 方法中对引用类型的字段也进行递归克隆。
在Go中,没有内建的 clone() 方法。复制通常通过创建一个新实例并手动复制字段值来完成。对于引用类型(如切片、映射、指针),需要特别注意是复制引用还是复制底层数据。

5. 适用场景 (When to Use)

  • 当一个系统应该独立于它的产品创建、构成和表示时,并且你想要在运行时指定实例化的类。
  • 当要实例化的类是在运行时指定时,例如,通过动态装载。
  • 为了避免创建一个与产品类层次平行的工厂类层次时(即不想为了创建不同产品而创建一堆工厂类)。
  • 当一个类的实例只能有几种不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
  • 创建对象的成本很高:例如,对象初始化需要大量计算、I/O操作或网络通信。
  • 需要创建大量相似对象:只有少量属性不同的对象。
  • 系统需要在运行时动态添加或修改可创建的对象类型

6. 优缺点 (Pros and Cons)

优点:

  1. 性能提升:对于创建成本高的对象,克隆比重新创建更快。
  2. 简化对象创建:可以复制一个已经初始化好的复杂对象,避免重复的初始化逻辑。
  3. 灵活性高:可以在运行时动态地获取和复制原型对象。
  4. 对客户端隐藏具体类型:客户端只需要知道抽象原型接口即可创建对象。

缺点:

  1. 需要为每个类实现克隆方法:每个需要作为原型的类都必须实现 clone() 方法,这可能比较繁琐,特别是当类层次结构很深或包含许多字段时。
  2. 深拷贝实现复杂:正确实现深拷贝可能比较复杂,需要仔细处理所有引用类型的成员,以避免意外共享或循环引用问题。
  3. 可能违反开闭原则(如果克隆逻辑复杂):如果克隆逻辑非常复杂且依赖于具体类的内部结构,当具体类修改时,克隆方法可能也需要修改。

7. 实现方式 (Implementations)

让我们通过一个图形绘制的例子来看看原型模式的实现。假设我们有不同形状(圆形、矩形)的对象,它们可以被克隆。

抽象原型 (Shape)
// shape.go
package shape

import "fmt"

// Shape 抽象原型接口
type Shape interface {
	Clone() Shape
	Draw()
	SetID(id string)
	GetID() string
}
// Shape.java
package com.example.shape;

// 抽象原型接口
// Java 中通常让原型类实现 Cloneable 接口并重写 clone() 方法
public interface Shape extends Cloneable { // Cloneable 是一个标记接口
    Shape cloneShape(); // 自定义一个更明确的克隆方法名
    void draw();
    void setId(String id);
    String getId();
}
具体原型 (Circle, Rectangle)
// circle.go
package shape

import "fmt"

// Circle 具体原型
type Circle struct {
	ID     string
	Radius int
	X, Y   int // 圆心坐标
}

func NewCircle(id string, radius, x, y int) *Circle {
	return &Circle{ID: id, Radius: radius, X: x, Y: y}
}

func (c *Circle) SetID(id string) { c.ID = id }
func (c *Circle) GetID() string   { return c.ID }

// Clone 实现浅拷贝,因为 Circle 的字段都是值类型或string (string在Go中是值类型行为)
func (c *Circle) Clone() Shape {
	return &Circle{
		ID:     c.ID + "_clone", // 给克隆体一个新ID
		Radius: c.Radius,
		X:      c.X,
		Y:      c.Y,
	}
}

func (c *Circle) Draw() {
	fmt.Printf("Drawing Circle [ID: %s, Radius: %d, Center: (%d,%d)]\n", c.ID, c.Radius, c.X, c.Y)
}

// rectangle.go
package shape

import "fmt"

// Rectangle 具体原型
type Rectangle struct {
	ID            string
	Width, Height int
	X, Y          int // 左上角坐标
}

func NewRectangle(id string, width, height, x, y int) *Rectangle {
	return &Rectangle{ID: id, Width: width, Height: height, X: x, Y: y}
}

func (r *Rectangle) SetID(id string) { r.ID = id }
func (r *Rectangle) GetID() string   { return r.ID }

// Clone 实现浅拷贝
func (r *Rectangle) Clone() Shape {
	return &Rectangle{
		ID:     r.ID + "_clone",
		Width:  r.Width,
		Height: r.Height,
		X:      r.X,
		Y:      r.Y,
	}
}

func (r *Rectangle) Draw() {
	fmt.Printf("Drawing Rectangle [ID: %s, Width: %d, Height: %d, TopLeft: (%d,%d)]\n", r.ID, r.Width, r.Height, r.X, r.Y)
}
// Circle.java
package com.example.shape;

// 具体原型
public class Circle implements Shape {
    private String id;
    private int radius;
    private Point center; // 假设 Point 是一个自定义的可变类

    public Circle(String id, int radius, int x, int y) {
        this.id = id;
        this.radius = radius;
        this.center = new Point(x, y);
        System.out.println("Circle created with ID: " + id);
    }

    // 私有构造,用于克隆
    private Circle(String id, int radius, Point center) {
        this.id = id;
        this.radius = radius;
        this.center = center; // 注意这里,如果是浅拷贝,center会被共享
    }

    @Override
    public void setId(String id) { this.id = id; }
    @Override
    public String getId() { return this.id; }
    public int getRadius() { return radius; }
    public Point getCenter() { return center; }
    public void setCenter(int x, int y) { this.center.setX(x); this.center.setY(y); }

    @Override
    public Shape cloneShape() {
        System.out.println("Cloning Circle with ID: " + this.id);
        Circle clonedCircle = null;
        try {
            // 默认的 Object.clone() 是浅拷贝
            clonedCircle = (Circle) super.clone(); 
            // 为了实现深拷贝,需要对可变引用类型字段进行单独克隆
            clonedCircle.id = this.id + "_clone"; // 通常给克隆体新ID
            clonedCircle.center = (Point) this.center.clone(); // 假设 Point 也实现了 Cloneable 和 clone()
        } catch (CloneNotSupportedException e) {
            // This should not happen if we implement Cloneable
            e.printStackTrace();
        }
        return clonedCircle;
    }

    @Override
    public void draw() {
        System.out.printf("Drawing Circle [ID: %s, Radius: %d, Center: %s]%n", id, radius, center);
    }
}

// Rectangle.java
package com.example.shape;

public class Rectangle implements Shape {
    private String id;
    private int width;
    private int height;
    private Point topLeft; // 可变引用类型

    public Rectangle(String id, int width, int height, int x, int y) {
        this.id = id;
        this.width = width;
        this.height = height;
        this.topLeft = new Point(x,y);
        System.out.println("Rectangle created with ID: " + id);
    }

    @Override
    public void setId(String id) { this.id = id; }
    @Override
    public String getId() { return this.id; }
    public Point getTopLeft() { return topLeft; }
    public void setTopLeft(int x, int y) { this.topLeft.setX(x); this.topLeft.setY(y); }

    @Override
    public Shape cloneShape() {
        System.out.println("Cloning Rectangle with ID: " + this.id);
        Rectangle clonedRectangle = null;
        try {
            clonedRectangle = (Rectangle) super.clone();
            clonedRectangle.id = this.id + "_clone";
            clonedRectangle.topLeft = (Point) this.topLeft.clone(); // 深拷贝 Point
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clonedRectangle;
    }

    @Override
    public void draw() {
        System.out.printf("Drawing Rectangle [ID: %s, Width: %d, Height: %d, TopLeft: %s]%n", id, width, height, topLeft);
    }
}

// Point.java (辅助类,用于演示深拷贝)
package com.example.shape;

public class Point implements Cloneable {
    private int x;
    private int y;

    public Point(int x, int y) { this.x = x; this.y = y; }
    public int getX() { return x; }
    public void setX(int x) { this.x = x; }
    public int getY() { return y; }
    public void setY(int y) { this.y = y; }

    @Override
    public String toString() { return "(" + x + "," + y + ")"; }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // Point 只包含基本类型,所以 super.clone() 已经是深拷贝效果了
        // 如果 Point 内部还有其他引用类型,则需要进一步处理
        return super.clone();
    }
}
原型管理器 (可选, PrototypeManager / ShapeCache)

有时会引入一个原型管理器类,用于存储和检索原型实例。客户端向管理器请求一个特定类型的原型,然后克隆它。

// shape_cache.go
package shape

import "fmt"

// ShapeCache 原型管理器
type ShapeCache struct {
	prototypes map[string]Shape
}

func NewShapeCache() *ShapeCache {
	cache := &ShapeCache{prototypes: make(map[string]Shape)}
	cache.loadCache()
	return cache
}

// loadCache 初始化原型实例并存储
func (sc *ShapeCache) loadCache() {
	circle := NewCircle("circle1", 10, 0, 0)
	rectangle := NewRectangle("rect1", 20, 10, 0, 0)

	sc.prototypes[circle.GetID()] = circle
	sc.prototypes[rectangle.GetID()] = rectangle
	fmt.Println("ShapeCache: Prototypes loaded.")
}

// GetShape 克隆并返回指定ID的原型
func (sc *ShapeCache) GetShape(id string) (Shape, error) {
	prototype, found := sc.prototypes[id]
	if !found {
		return nil, fmt.Errorf("prototype with id '%s' not found", id)
	}
	return prototype.Clone(), nil
}

// AddShape 允许运行时添加新的原型
func (sc *ShapeCache) AddShape(id string, shape Shape) {
    sc.prototypes[id] = shape
    fmt.Printf("ShapeCache: Prototype '%s' added.\n", id)
}
// ShapeCache.java
package com.example.shape;

import java.util.Hashtable;

// 原型管理器
public class ShapeCache {
    private static Hashtable<String, Shape> shapeMap = new Hashtable<>();

    public static Shape getShape(String shapeId) throws CloneNotSupportedException {
        Shape cachedShape = shapeMap.get(shapeId);
        if (cachedShape == null) {
            System.err.println("ShapeCache: Prototype with ID '" + shapeId + "' not found.");
            return null;
        }
        System.out.println("ShapeCache: Returning clone of prototype with ID: " + shapeId);
        return cachedShape.cloneShape(); // 调用我们自定义的克隆方法
    }

    // loadCache 会加载每种形状的实例,并将它们存储在 Hashtable 中
    public static void loadCache() {
        System.out.println("ShapeCache: Loading initial prototypes...");
        Circle circle = new Circle("circle-proto", 10, 0, 0);
        shapeMap.put(circle.getId(), circle);

        Rectangle rectangle = new Rectangle("rect-proto", 20, 10, 5, 5);
        shapeMap.put(rectangle.getId(), rectangle);
        System.out.println("ShapeCache: Prototypes loaded.");
    }

    // 允许运行时添加新的原型
    public static void addPrototype(String id, Shape shape) {
        shapeMap.put(id, shape);
        System.out.println("ShapeCache: Prototype '" + id + "' added.");
    }
}
客户端使用
// main.go (示例用法)
/*
package main

import (
	"fmt"
	"./shape"
)

func main() {
	cache := shape.NewShapeCache()

	// 从缓存获取原型并克隆
	circle1, err := cache.GetShape("circle1")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	circle1.Draw() // ID: circle1_clone

	rect1, err := cache.GetShape("rect1")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	rect1.Draw() // ID: rect1_clone

	// 修改克隆体的属性
	circle1.SetID("myCustomCircle")
	// 如果是 Circle 类型,可以进行类型断言来访问特定属性
	if c, ok := circle1.(*shape.Circle); ok {
		c.Radius = 100
		c.X = 50
	}
	circle1.Draw() // ID: myCustomCircle, Radius: 100, Center: (50,0)

	// 原始原型不受影响
	originalCircle, _ := cache.GetShape("circle1") // 再次获取会重新克隆
	originalCircleProto := cache.prototypes["circle1"] // 直接访问原型 (不推荐直接修改原型)
	fmt.Println("--- Original prototype vs new clone from cache ---")
	originalCircleProto.Draw() // ID: circle1, Radius: 10
	originalCircle.Draw()      // ID: circle1_clone, Radius: 10 (新克隆的)

    // 运行时添加新原型
    trianglePrototype := shape.NewTriangle("triangle-proto", 5, 10) // 假设有 Triangle 类型
    cache.AddShape(trianglePrototype.GetID(), trianglePrototype)

    clonedTriangle, _ := cache.GetShape("triangle-proto")
    if clonedTriangle != nil {
        clonedTriangle.Draw()
    }
}

// 假设添加一个 Triangle 类型 (triangle.go)
/*
package shape
import "fmt"
type Triangle struct { ID string; Base, Height int }
func NewTriangle(id string, base, height int) *Triangle { return &Triangle{id, base, height} }
func (t *Triangle) SetID(id string) { t.ID = id }
func (t *Triangle) GetID() string   { return t.ID }
func (t *Triangle) Clone() Shape    { return &Triangle{t.ID + "_clone", t.Base, t.Height} }
func (t *Triangle) Draw()           { fmt.Printf("Drawing Triangle [ID: %s, Base: %d, Height: %d]\n", t.ID, t.Base, t.Height) }
*/
// Main.java (示例用法)
/*
package com.example;

import com.example.shape.Circle;
import com.example.shape.Rectangle;
import com.example.shape.Shape;
import com.example.shape.ShapeCache;

public class Main {
    public static void main(String[] args) {
        ShapeCache.loadCache(); // 加载原型

        try {
            System.out.println("--- Cloning and using shapes ---");
            Shape clonedCircle1 = ShapeCache.getShape("circle-proto");
            if (clonedCircle1 != null) {
                clonedCircle1.draw(); // ID: circle-proto_clone
            }

            Shape clonedRectangle1 = ShapeCache.getShape("rect-proto");
            if (clonedRectangle1 != null) {
                clonedRectangle1.draw(); // ID: rect-proto_clone
            }

            System.out.println("\n--- Modifying a cloned shape ---");
            // 修改克隆体的属性
            if (clonedCircle1 != null) {
                clonedCircle1.setId("myCustomCircle");
                if (clonedCircle1 instanceof Circle) {
                    Circle customCircle = (Circle) clonedCircle1;
                    customCircle.setCenter(100, 100); // 修改 Point 对象
                }
                clonedCircle1.draw(); // ID: myCustomCircle, Center: (100,100)
            }

            System.out.println("\n--- Verifying original prototype is unchanged ---");
            // 原始原型不受影响 (因为我们实现了深拷贝 Point)
            Shape originalCircleProto = ShapeCache.shapeMap.get("circle-proto"); // 直接访问原型 (不推荐)
            if (originalCircleProto != null) {
                System.out.print("Original Prototype in Cache: ");
                originalCircleProto.draw(); // ID: circle-proto, Center: (0,0)
            }

            Shape newlyClonedCircle = ShapeCache.getShape("circle-proto");
            if (newlyClonedCircle != null) {
                System.out.print("Newly Cloned from Cache: ");
                newlyClonedCircle.draw(); // ID: circle-proto_clone, Center: (0,0)
            }

            // 演示如果 Point 是浅拷贝会发生什么
            // 如果 Circle.cloneShape() 中对 center 只是 clonedCircle.center = this.center;
            // 那么修改 customCircle.setCenter(100,100) 会同时修改 originalCircleProto 的 center

            System.out.println("\n--- Adding a new prototype at runtime ---");
            Circle newProto = new Circle("circle-large-proto", 50, 10, 10);
            ShapeCache.addPrototype(newProto.getId(), newProto);

            Shape clonedLargeCircle = ShapeCache.getShape("circle-large-proto");
            if(clonedLargeCircle != null) {
                clonedLargeCircle.draw();
            }

        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
*/

8. 总结

原型模式通过复制(克隆)现有对象来创建新对象,从而在特定场景下(如对象创建成本高、需要大量相似对象)提供了一种高效且灵活的对象创建方式。核心在于实现 clone() 方法,并正确处理深拷贝与浅拷贝的问题。当与原型管理器结合使用时,还可以实现运行时的动态产品配置。

记住它的核心:克隆现有对象,高效创建

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

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

相关文章

java 进阶 1.0.3

Thread API说明 自己滚去看文档 CPU线程调度 每一个线程的优先使用权都是系统随机分配的&#xff0c;人人平等 谁先分配到就谁先用 也可以耍赖&#xff0c;就是赋予某一个线程拥有之高使用权&#xff1a;优先级 这样的操作就叫做线程调度 最基本的是系统轮流获得 java的做法是抢…

从 Docker 到 runC

从 Docker 到 runC:容器底层原理详解 目录 1. Docker 与 runC 的关系 2. Docker 的核心组件 3. runC 的核心功能 4. 实战示例:从 Docker 到 runC 4.1 示例场景:运行一个简单容器 4.2 Docker 底层调用 runC 的流程 4.3 查看 runC 的调用 4.4 直接调用 runC 创建容器 …

PET,Prompt Tuning,P Tuning,Lora,Qlora 大模型微调的简介

概览 到2025年&#xff0c;虽然PET&#xff08;Pattern-Exploiting Training&#xff09;和Prompt Tuning在学术界仍有探讨&#xff0c;但在工业和生产环境中它们已基本被LoRA/QLoRA等参数高效微调&#xff08;PEFT&#xff09;方法取代 。LoRA因其实现简单、推理零开销&#…

02-jenkins学习之旅-基础配置

0 配置主路径 jenkins安装目录下找到jenkins.xml文件&#xff0c;C:\ProgramData\Jenkins\.jenkins目录下会存放jenkins相关的配置信息。 1 jdk配置 jenkins是java开发开源的项目&#xff0c;进而服务器需要jdk环境 1.1 服务器安装jdk 1.2 jenkins jdk配置 2 git配置 在je…

Appium+python自动化(三)- SDK Manager

简介 一开始打算用真机做的&#xff0c;所以在前边搭建环境时候就没有下载SDK&#xff0c;但是考虑到绝大多数人都没有真机&#xff0c;所以顺应民意整理一下模拟器。SDK顾名思义&#xff0c;Android SDK Manager就是一个Android软件开发工具包管理器&#xff0c;就像一个桥梁&…

3D Gaussian Splatting for Real-Time Radiance Field Rendering——文章方法精解

SfM → Point-NeRF → 3D Gaussian Splatting &#x1f7e6;SfM Structure-from-Motion&#xff08;运动恢复结构&#xff0c;简称 SfM&#xff09;是一种计算机视觉技术&#xff0c;可以&#xff1a; 利用多张从不同角度拍摄的图像&#xff0c;恢复出场景的三维结构和相机的…

【Unity实战笔记】第二十四 · 使用 SMB+Animator 实现基础战斗系统

转载请注明出处&#xff1a;&#x1f517;https://blog.csdn.net/weixin_44013533/article/details/146409453 作者&#xff1a;CSDN|Ringleader| 1 结构 1.1 状态机 1.2 SMB 2 代码实现 2.1 核心控制 Player_Base_SMB 继承 StateMachineBehaviour &#xff0c;控制变量初始…

【Java高阶面经:消息队列篇】22、消息队列核心应用:高并发场景下的解耦、异步与削峰

一、消息队列:分布式系统的核心枢纽 在分布式架构日益普及的今天,消息队列(Message Queue, MQ)已成为解决系统复杂性的核心组件。它通过异步通信、系统解耦和流量控制等能力,有效应对高并发场景下的数据流动挑战。 1.1 核心特性:异步、解耦与弹性 1.1.1 异步通信:释放…

软媒魔方——一款集合多种系统辅助组件的软件

停更4年&#xff0c;但依旧吊炸天&#xff01; 亲们&#xff0c;是不是觉得电脑用久了就像老牛拉车&#xff0c;慢得让人着急&#xff1f;别急&#xff0c;我今天要给大家安利一个超好用的电脑优化神器——软媒魔方&#xff01; 软件介绍 首先&#xff0c;这货真心是免费的&a…

多路径可靠传输协议(比如 MPTCP)为什么低效

可靠就不能多路径&#xff0c;多路径求可靠必然要多费劲。这不难理解&#xff0c;多路径必异步&#xff0c;这无疑增加了可靠性判断的难度。 前文 多路径传输(比如 MPTCP)对性能的意义 阐述了作为单连接的多子流 MPTCP 对传输性能的意义是无意义&#xff0c;本文接着阐述作为隧…

塔能高温冰蓄冷技术:工厂能耗精准节能的创新之路

在工厂的能耗构成中&#xff0c;制冷系统是重要的耗能环节。传统的水蓄冷和冰蓄冷技术在实际应用中存在一些局限性&#xff0c;难以满足工厂对节能和成本控制的更高要求。塔能科技的高温冰蓄冷技术&#xff0c;凭借其独特的优势&#xff0c;为工厂能耗精准节能提供了创新的解决…

内存优化笔记1

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 问题提出 在很多工业软件中&#xff0c;需要对对象进行微分细化&#xff0c;这样会产生很多&#xff08;几百万到几千万&#xff09;对象。随着业务的发展&#xff0c…

人脸识别,使用 deepface + api + flask, 改写 + 调试

1. 起因&#xff0c; 目的&#xff0c; 感受: github deepface 这个项目写的很好&#xff0c; 继续研究使用这个项目&#xff0c;改写 api。增加一个前端 flask app 2. 先看效果 3. 过程: 大力改写原始项目中 api 这部分的代码&#xff0c; 原始项目的文件结构太繁杂了: 我把…

代码管理平台Gitlab如何通过快解析实现远程访问?

一、Gitlab功能介绍 Gitlab是被广泛使用的基于git的开源代码管理平台&#xff0c;用于管理、存储开发人员代码&#xff0c;同时可以协同开发 二、外网试用Gitlab遇到的问题 运维人员将Gitlab服务器部署在总部机房&#xff0c;而分公司开发人员和出差运维人员就无法访问Gitlab…

基于SpringBoot+Vue的足球青训俱乐部管理后台系统的设计与开发

项目背景与概述 随着足球青训行业的快速发展&#xff0c;如何高效、规范地管理学员、教练以及课程等日常工作&#xff0c;成为了青训俱乐部运营的重要课题。为了提升俱乐部的管理效率与用户体验&#xff0c;基于 Spring Boot 和 Vue.js 开发了一个 足球青训俱乐部管理后台系统…

线程调度与单例模式:wait、notify与懒汉模式解析

一.wait 和 notify&#xff08;等待 和 通知&#xff09; 引入 wait notify 就是为了能够从应用层面&#xff0c;干预到多个不同线程代码的执行顺序&#xff0c;可以让后执行的线程主动放弃被调度的机会&#xff0c;等先执行的线程完成后通知放弃调度的线程重新执行。 自助取…

MySQL中TCP和套接字SSL加密连接行为分析

目录 一、前言 二、背景 三、参数介绍 3.1、 have_openssl 3.2、have_ssl 3.3、require_secure_transport 四、--ssl-modemode 五、CREATE USER SSL/TLS选项 六、问题验证 6.1、使用套接字连接 6.2、使用TCP连接 七、分析与总结 一、前言 SSL&#xff08;Secure S…

php本地 curl 请求证书问题解决

错误: cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for 解决方案 在php目录下创建证书文件夹, 执行下面生成命令, 然后在php.ini 文件中配置证书路径; 重启环境 curl --eta…

爱普生晶振赋能UWB汽车数字钥匙,解锁未来出行新方式

随着科技的发展&#xff0c;尤其是国产新能源汽车的崛起&#xff0c;相信大家对数字钥匙的概念已经不陌生了&#xff0c;通过手机、智能穿戴实现对汽车的多功能控制已经是很多汽车的标配。但是目前数字钥匙也有一定的局限性&#xff0c;比如定位不准、安全性不强等等&#xff0…

电子电路:深入理解电磁耦合的定义与应用

电场和磁场是独立存在的吗&#xff1f;&#xff0c;但实际上根据麦克斯韦理论&#xff0c;它们是同一现象的两个方面&#xff0c;通过变化相互产生。这时候需要强调时变场的重要性&#xff0c;以及静态场和动态场的区别。 通过电磁波的概念&#xff0c;说明电磁耦合如何导致电…