游戏开发中常用的设计模式
目录
- 前言
- 一、工厂模式
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
- 二、单例模式
- 三、观察者模式
- 观察者模式的优势
- 四、状态模式
- 状态模式的优势
- 五、策略模式
- 策略模式的优势
- 六、组合模式
- 七、命令模式
- 八、装饰器模式
- 策略模式与状态模式有什么区别呢?
前言
本文介绍了游戏开发中常用的设计模式,如工厂模式用于创建对象,单例模式确保全局唯一,观察者模式实现对象间事件通知,状态模式管理对象状态转换,策略模式提供行为选择,组合模式构建复杂对象结构,命令模式分离操作与执行,装饰模式动态扩展功能。
- 单例模式:用于确保在游戏中只存在一个实例,例如游戏管理器(Game Manager)或资源管理器(Resource Manager)。
- 工厂模式:用于创建对象实例,例如创建不同类型的敌人(Enemy)或武器(Weapon)。
- 观察者模式:用于实现对象间的事件通知,例如实现角色(Character)与任务(Quest)的交互。
- 状态模式:用于管理游戏中对象的状态转换,例如角色在游戏中的状态(生命值、能量等)。
- 策略模式:用于实现不同的算法和行为,例如实现不同的AI(Artificial Intelligence)策略。
- 组合模式:用于创建和管理游戏中的复杂对象结构,例如实现游戏中的菜单(Menu)或场景(Scene)。
- 命令模式:用于将操作(操作)与其执行分离,例如实现游戏中的键盘快捷键。
- 装饰器模式:通过创建一个包装对象,即装饰器,来包裹真正的对象,并且在保持接口的前提下,为它提供额外的功能。
一、工厂模式
工厂模式是一种常用的设计模式,用于创建对象,它能够隐藏创建对象的复杂性,并且使代码更加灵活。在游戏开发中,工厂模式通常用于创建游戏对象、敌人、道具等。
选择合适的工厂模式:
- 简单工厂模式:定义一个工厂类,根据参数的不同返回不同类的实例。适用于对象种类较少且明确的情况。
- 工厂方法模式:定义一个接口或抽象类,由子类实现具体的创建逻辑,工厂类负责调用这些子类的方法来创建对象。这种模式支持动态决定实例化哪一个类,而不必知道要实例化的具体类。
- 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。适用于需要创建一系列相关或相互依赖对象的场景。
简单工厂模式
public class SimpleFactory
{public static T Create<T>(string type){switch (type){case "x":return (T)A();case "y":return (T)B();default:throw new ArgumentException("未知类型");}}}//使用工厂类来创建游戏对象:
SimpleFactory factory = new SimpleFactory();A a = factory.Create<A>("x");
B b = factory.Create<B>("y");
工厂方法模式
//首先我们定义一个接口,表示我们要创建的对象:
public interface IGameObject
{void Update();
}//创建具体的游戏对象类:
public class Player : IGameObject
{public void Update(){Console.WriteLine("Player is updating.");}
}public class Enemy : IGameObject
{public void Update(){Console.WriteLine("Enemy is updating.");}
}//创建一个工厂类,用于创建游戏对象
public class GameObjectFactory
{public IGameObject CreateGameObject(string type){switch (type){case "Player":return new Player();case "Enemy":return new Enemy();default:throw new ArgumentException($"Invalid game object type: {type}");}}
}//使用工厂类来创建游戏对象:
GameObjectFactory factory = new GameObjectFactory();IGameObject player = factory.CreateGameObject("Player");
player.Update();IGameObject enemy = factory.CreateGameObject("Enemy");
enemy.Update();
抽象工厂模式
public abstract class AbstractFactory{public abstract IProduct Product { get; }}public class RealFactory : AbstractFactory{public override IProduct Product => new RealProduct();}public class Client{private AbstractFactory factory;public Client(AbstractFactory factory){this.factory = factory;}public void UseProduct(){IProduct product = factory.Product;product.Use();}}
二、单例模式
单例模式是一种常用的设计模式,用于确保一个类只有一个实例,并提供全局访问点。在游戏开发中,单例模式通常用于管理全局状态、资源池等。
public class GameManager
{private static GameManager _instance;// 私有构造函数,确保只能在类内部创建实例private GameManager(){// 初始化游戏管理器Console.WriteLine("GameManager initialized.");}// 全局访问点public static GameManager Instance{get{if (_instance == null){_instance = new GameManager();///懒汉式}return _instance;}}// 游戏管理器的功能public void StartGame(){Console.WriteLine("Game started.");}
}///实例化
GameManager gameManager = GameManager.Instance;gameManager.StartGame(); // Output: "Game started."GameManager gameManager2 = GameManager.Instance; // 和 gameManager 引用同一个对象
三、观察者模式
观察者模式在游戏开发中通常用于红点系统,实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,这违反了面向对象的设计原则。
观察者模式的主要角色如下:
- 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
- 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
using System.Collections.Generic;
using UnityEngine;//抽象类 观察者
public interface Observer
{void response(); //反应
}//被观察者
public class ConcreteSubject
{public static ConcreteSubject _instance = null;protected List<Observer> observers = new List<Observer>();public void Init(){}public static ConcreteSubject Instance(){if (_instance == null){_instance = new ConcreteSubject();}return _instance;}//增加观察者方法public void add(Observer observer){observers.Add(observer);}//删除观察者方法public void remove(Observer observer){observers.Remove(observer);}public void notifyObserver(){Debug.Log("具体目标发生改变...");foreach(Observer obs in observers){obs.response();}}
}//具体观察者1
public class ConcreteObserver1 : MonoBehaviour , Observer
{private void Start(){ConcreteSubject.Instance().add(this);}public void response(){Debug.Log("具体观察者1作出反应!");}private void OnDestroy(){ConcreteSubject.Instance().remove(this);}
}//具体观察者2
public class ConcreteObserver2 : MonoBehaviour, Observer
{private void Start(){ConcreteSubject.Instance().add(this);}public void response(){Debug.Log("具体观察者2作出反应!");}private void OnDestroy(){ConcreteSubject.Instance().remove(this);}}
观察者模式的优势
- 松散耦合:观察者模式允许构建松散耦合的类关系,这在游戏开发中非常重要,因为它可以降低系统各部分之间的耦合度。
- 提高系统的灵活性和可维护性:观察者模式不仅能够降低系统各部分之间的耦合度,还能提高系统的灵活性和可维护性。
- 解耦和事件驱动:观察者模式特别适用于需要响应UI事件或进行成就系统设计的场景,它允许完全解耦控制逻辑和UI事件处理。
四、状态模式
状态模式(State Pattern)是一种行为设计模式,它允许一个对象在其内部状态改变时改变其行为。在游戏开发中,状态模式常用于实现角色的不同行为状态切换,例如玩家角色的行走、奔跑、跳跃、攻击等不同状态。每个状态通过持有Context的引用,来实现状态转移。
// 定义抽象状态类
public abstract class CharacterState
{protected Character character;///this is Contextpublic void SetCharacter(Character _character){this.character = _character;}// 抽象方法,子类需要实现具体行为public abstract void Update();
}// 具体状态类:IdleState
public class IdleState : CharacterState
{public override void Update(){Debug.Log("角色处于闲置状态");// 检查是否应该转换到其他状态,如按下移动键则切换至MoveStateif (Input.GetKey(KeyCode.W)){character.ChangeState(new MoveState());}}
}// 具体状态类:MoveState
public class MoveState : CharacterState
{public override void Update(){Debug.Log("角色正在移动");// 检查是否应返回闲置状态或切换至其他状态if (!Input.GetKey(KeyCode.W)){character.ChangeState(new IdleState());}}
}// 角色类持有当前状态并处理状态切换
public class Character : MonoBehaviour
{private CharacterState currentState;public void ChangeState(CharacterState newState){if (currentState != null){currentState.SetCharacter(null);}currentState = newState;currentState.SetCharacter(this);}void Update(){currentState.Update();}
}
状态模式的优势
- 封装状态转换:状态模式将状态转换的逻辑封装到状态类内部,使得状态之间的切换变得明确和集中。
- 简化复杂条件逻辑:通过将不同状态的行为分割开来,状态模式减少了对象间的相互依赖,提高了可维护性和可扩展性。
- 清晰的状态管理:特别是在Unity引擎中,状态模式帮助游戏场景的切换和管理变得更加清晰。
五、策略模式
如何在Unity中实现策略模式以优化角色行为和AI策略?
在Unity中实现策略模式以优化角色行为和AI策略,可以按照以下步骤进行:
- 定义策略类:首先,将不同的行为或算法封装成独立的类(策略)。每个策略类代表一种特定的行为或算法。例如,可以为角色攻击、移动、防御等行为分别创建一个策略类。
- 使用接口或抽象类:为了使策略类之间可以互相替换,建议使用接口或抽象类来定义每种策略需要实现的方法。这样可以确保所有策略类都遵循相同的协议。
- 动态选择和切换策略:在运行时根据需要动态选择和切换不同的策略。这可以通过检查游戏中的某些条件或事件来实现。例如,当敌人接近玩家时,可以选择攻击策略;当敌人远离玩家时,可以选择逃跑策略。
- 避免条件语句过多:使用策略模式可以有效减少代码中的条件语句,从而避免代码变得臃肿和难以维护。通过将具体算法实现从具体的业务逻辑中分离出来,可以让算法的变化独立于使用算法的客户端。
- 示例代码:以下是一个简单的示例代码,展示了如何在Unity中实现策略模式:
// 攻击策略类
public class AttackStrategy : IStrategy
{public void PerformAction(){Debug.Log("Attacking");}
}// 移动策略类
public class MoveStrategy : IStrategy
{public void PerformAction(){Debug.Log("Moving");}
}// 防御策略类
public class DefenseStrategy : IStrategy
{public void PerformAction(){Debug.Log("防御");}
}// 策略选择器
public class StrategySelector
{private IStrategy _strategy;public void SetStrategy(IStrategy strategy){_strategy = strategy;}public void PerformAction(){_strategy.PerformAction();}
}// 主脚本
public class Player : MonoBehaviour
{private StrategySelector _selector;void Start(){_selector = new StrategySelector();_selector.SetStrategy(new AttackStrategy());_selector.PerformAction(); // 输出:Attacking// 根据条件切换策略if (playerHealth < 50){_selector.SetStrategy(new DefenseStrategy());_selector.PerformAction(); // 输出:防御}}
}
策略模式的优势
- 算法独立性:策略模式使得算法可以独立于使用它的客户端变化。这意味着可以根据不同的游戏状态、角色类型或玩家选择,动态地改变游戏的行为。
- 灵活性和多态性:通过将算法封装在独立的策略类中,策略模式提供了一种更灵活的方式来处理多态行为。这使得算法的变化不会影响到使用这些算法的客户。
- 简化复杂条件逻辑:策略模式能够减少对象间的相互依赖,并且将与特定状态相关的行为局部化到一个状态中,从而满足单一职责原则。游戏开发设计模式之策略模式
六、组合模式
组合模式一般适用于对象的部分-整体层次分明。比如游戏中的文件夹目录结构的管理。
树状结构图
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 组合模式
/// </summary>
public class CompositeMode : MonoBehaviour
{private void Start(){INode root = new CompositeNode("Character");INode leftHand = new LeafNode("LeftHand");INode body = new CompositeNode("Body");INode rightHand = new LeafNode("RightHand");root.AddChildNode(leftHand, body, rightHand);INode leftFoot = new LeafNode("LeftFoot");INode rightFoot = new LeafNode("RightFoot");body.AddChildNode(leftFoot, rightFoot);ShowAllNode(root);}/// <summary>/// 显示节点和其所有子节点/// </summary>private void ShowAllNode(INode node){Debug.Log(node.Name);List<INode> childNodeList = node.ChildNodeList;if (node == null || childNodeList == null){return;}foreach (INode item in childNodeList){ShowAllNode(item);}}
}/// <summary>
/// 节点抽象类
/// </summary>
public abstract class INode
{protected string mName;public string Name { get { return mName; } }protected List<INode> mChildNodeList;public List<INode> ChildNodeList { get { return mChildNodeList; } }public INode(string name){mChildNodeList = new List<INode>();mName = name;}//添加、移除、获取子节点public abstract void AddChildNode(INode node);//如果我们想可以一次添加多个子节点,就可以这样写public abstract void AddChildNode(params INode[] nodes);public abstract void RemoveChildNode(INode node);public abstract INode GetChildNode(int index);}
/// <summary>
/// 叶子节点
/// </summary>
public class LeafNode : INode
{public LeafNode(string name) : base(name){}//叶子节点无子节点public override void AddChildNode(INode node){throw new System.NotImplementedException();}public override void AddChildNode(params INode[] nodes){throw new System.NotImplementedException();}public override INode GetChildNode(int index){throw new System.NotImplementedException();}public override void RemoveChildNode(INode node){throw new System.NotImplementedException();}
}
/// <summary>
/// 非叶子节点
/// </summary>
public class CompositeNode : INode
{public CompositeNode(string name) : base(name){}public override void AddChildNode(INode node){mChildNodeList.Add(node);}public override void AddChildNode(params INode[] nodes){foreach (INode node in nodes){mChildNodeList.Add(node);}}public override void RemoveChildNode(INode node){if (mChildNodeList.Contains(node) == false){Debug.LogError(node + "在子节点中不存在");return;}mChildNodeList.Remove(node);}public override INode GetChildNode(int index){if ((index>=0 && index<mChildNodeList.Count)==false){Debug.LogError(index + "下标不存在");return null;}return mChildNodeList[index];}}
七、命令模式
八、装饰器模式
策略模式与状态模式有什么区别呢?
现在我们知道,状态模式和策略模式的结构是相似的,但它们的意图不同。让我们重温一下它们的主要不同之处:
- 策略模式封装了一组相关算法,它允许Client在运行时使用可互换的行为;状态模式帮助一个类在不同的状态显示不同的行为。
- 状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而通过从Context中分离出策略或算法,我们可以重用它们。
- 在状态模式中,每个状态通过持有Context的引用,来实现状态转移;但是每个策略都不持有Context的引用,它们只是被Context使用。
- 策略实现可以作为参数传递给使用它的对象,例如Collections.sort(),它的参数包含一个Comparator策略。另一方面,状态是Context对象自己的一部分,随着时间的推移,Context对象从一个状态转移到另一个状态。
- 虽然它们都符合OCP原则,策略模式也符合SRP原则(单一职责原则),因为每个策略都封装自己的算法,且不依赖其他策略。一个策略的改变,并不会导致其他策略的变化。
- 另一个理论上的不同:策略模式定义了对象“怎么做”的部分。例如,排序对象怎么对数据排序。状态模式定义了对象“是什么”和“什么时候做”的部分。例如,对象处于什么状态,什么时候处在某个特定的状态。
- 状态模式中很好的定义了状态转移的次序;而策略模式并无此需要:Client可以自由的选择任何策略。
- 一些常见的策略模式的例子是封装算法,例如排序算法,加密算法或者压缩算法。如果你看到你的代码需要使用不同类型的相关算法,那么考虑使用策略模式吧。而识别何时使用状态模式是很简单的:如果你需要管理状态和状态转移,但不想使用大量嵌套的条件语句,那么就是它了。
最后但最重要的一个不同之处是,策略的改变由Client完成;而状态的改变,由Context或状态自己。
参考文档:设计模式之:状态模式和策略模式的区别
相关文章:
游戏开发中常用的设计模式
目录 前言一、工厂模式简单工厂模式工厂方法模式抽象工厂模式 二、单例模式三、观察者模式观察者模式的优势 四、状态模式状态模式的优势 五、策略模式策略模式的优势 六、组合模式七、命令模式八、装饰器模式策略模式与状态模式有什么区别呢? 前言 本文介绍了游戏开发中常用…...
Android 11适配全攻略:从理论到实践
随着Google正式发布Android 11,开发者们迎来了新的挑战和机遇。Android 11不仅带来了全新的用户体验和功能提升,还要求开发者们对应用进行相应的适配,以确保应用的兼容性和稳定性。本文将从理论到实践,全面解析Android 11的适配攻…...
Grafana 统一可视化了,告警如何统一?
对于大部分公司,通常都不止一套监控、可观测性相关的系统,云上的、云下的,开源的、商业的,指标的、日志的、链路的,各个系统体验不同,权限难管,如何统一化并为各个团队赋能,是很多技…...
ubuntu20.04有亮度调节条但是调节时亮度不变
尝试了修改grub文件,没有作用,下载了brightness-controllor,问题解决了。 sudo add-apt-repository ppa:apandada1/brightness-controller sudo apt update sudo apt install brightness-controller 之后在应用软件中找到brightness-contro…...
抖音小程序一键获取手机号
前端代码组件 <button v-if"!isFromOrderList"class"get-phone-btn" open-type"getPhoneNumber"getphonenumber"onGetPhoneNumber">一键获取</button>// 获取手机号回调onGetPhoneNumber(e) {var that this tt.login({f…...
某政务行业基于 SeaTunnel 探索数据集成平台的架构实践
分享嘉宾:某政务公司大数据技术经理 孟小鹏 编辑整理:白鲸开源 曾辉 导读:本篇文章将从数据集成的基础概念入手,解析数据割裂给企业带来的挑战,阐述数据集成的重要性,并对常见的集成场景与工具进行阐述&…...
学习ASP.NET Core的身份认证(基于JwtBearer的身份认证8)
为进一步测试通过请求头传递token进行身份验证,在main.htm中增加layui的数据表格组件,并调用后台服务分页显示数据,后台分页查询数据接口如下所示(测试时,直接将数据写死到代码中,没有查询数据库࿰…...
Android 高德地图API(新版)
新版高德地图 前言正文一、创建应用① 获取PackageName② 获取调试版安全码SHA1③ 获取发布版安全码SHA1 二、配置项目① 导入SDK② 配置AndroidManifest.xml 三、获取当前定位信息① ViewBinding使用和导包② 隐私合规设置③ 权限请求④ 初始化定位⑤ 获取定位信息 四、显示地…...
51c~缺陷检测~合集2
我自己的原文哦~ https://blog.51cto.com/whaosoft/12386431 一、缺陷检测~使用深度学习1 这里研究工业ai, 在制造业中任何公司的主要目标都是为客户生产无缺陷产品。如果在产品开发过程中出现任何内部孔、凹坑、磨损或划痕(由于多种原因,从生产设备…...
强化学习与ai黑科技实例
一.强化学习简介和其应用 (1)强化学习,深度学习,有监督,无监督区别与联系。 1)强化学习讨论的核心就是智能机(agent)怎么在复杂,不确定的环境中最大化它能获得的奖励。 2)人工智能包括机器学习,机器学习包括有监督学习,无监督学习(例如聚类…...
《TikTok归来:机遇与挑战并存》
TikTok 回归:波折中的 “重生” 在全球社交媒体的版图中,TikTok 的存在无疑是一颗璀璨的明星。它以独特的短视频形式、强大的算法推荐以及丰富多样的内容,迅速风靡全球,吸引了数以亿计的用户。然而,其发展并非一帆风顺…...
Rust语言的正则表达式
Rust语言的正则表达式 正则表达式(Regular Expressions,简称Regex)是一种强大的文本处理工具,广泛应用于字符串的搜索、匹配、替换和解析。在Rust语言中,正则表达式的支持既高效又功能强大,非常适合开发者…...
三维扫描赋能文化:蔡司3D扫描仪让木质文化遗产焕发新生-沪敖3D
挪威文化历史博物馆在其修复工作中融入现代3D扫描技术,让数百年的历史焕发新生。 文化历史博物馆的工作 文化历史博物馆是奥斯陆大学的一个院系。凭借其在文化历史管理、研究和传播方面的丰富专业知识,该博物馆被誉为挪威博物馆研究领域的领先机构。馆…...
c# PDF文件合并工具
界面 主要用于发票PDF文件的合并。经常出差要报销的很有用。 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System…...
【16届蓝桥杯寒假刷题营】第1期DAY5
5.依依的询问最小值 - 蓝桥云课 问题描述 依依有个长度为 n 的序列 a,下标从 1 开始。 她有 m 次查询操作,每次她会查询下标区间在 [li,ri] 的 a 中元素和。她想知道你可以重新排序序列 a,使得这 m 次查询的总和最小。 求你求出 m 次…...
.NET周刊【1月第1期 2025-01-05】
国内文章 3款.NET开源、功能强大的通讯调试工具,效率提升利器! https://www.cnblogs.com/Can-daydayup/p/18631410 本文介绍了三款功能强大的.NET开源通讯调试工具,旨在提高调试效率。这些工具包括LLCOM,提供串口调试和自动化处…...
(7)(7.2) 围栏
文章目录 前言 1 通用设置 2 围栏类型 3 破坏栅栏行动 4 使用 RC 通道辅助开关启用栅栏 5 自动高度规避 6 在任务规划器中启用围栏 7 用于遥控飞行训练 8 MAVLink 支持 前言 ArduPilot 支持基于本机的圆柱形(“TinCan”)和多边形和/或圆柱形、…...
1166 Summit (25)
A summit (峰会) is a meeting of heads of state or government. Arranging the rest areas for the summit is not a simple job. The ideal arrangement of one area is to invite those heads so that everyone is a direct friend of everyone. Now given a set of tenta…...
linux_socket
udp 通信 server #include <iostream> #include <arpa/inet.h> #include <unistd.h> #include <cstring>using namespace std;#define UPORT 12511int main(){int sock socket(AF_INET, SOCK_DGRAM, 0); // 创建一个UDP套接字if (sock -1) {cout&…...
Linux探秘坊-------3.开发工具详解(2)
1.动静态库和动静态链接(操作) 静态库是指编译链接时,把库⽂件的代码全部加⼊到可执⾏⽂件中,因此⽣成的⽂件 ⽐较⼤,但在运⾏时也就不再需要库⽂件了。其后缀名⼀般为“.a” 动态库与之相反,在编译链接时并 没有把库⽂件的代码加⼊到可执⾏⽂件中 ,⽽…...
Mysql InnoDB B+Tree是什么?
“mysql中常用的数据库搜索引擎InnoDB,其索引通过BTree的方式进行构建。” 实在想不起来BTree是怎么一回事了。以点带线,将涉及到的数据结构一起复习一下。 文章目录 数据结构定义红黑树定义使命 BTree定义使命 BTree定义 InnoDB BTree 旋转与调整二叉排序树插入删…...
C语言进阶习题【1】指针和数组(1)——一维数组
1. 数组名的意义: sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。除此之外所有的数组名都表示首元素的地址。(一维数…...
2024:成长、创作与平衡的年度全景回顾
文章目录 1.前言2.突破自我:2024年个人成长与关键突破3.创作历程:从构想到落笔,2024年的文字旅程4.生活与学业的双重奏:如何平衡博客事业与个人生活5.每一步都是前行:2024年度的挑战与收获6.总结 1.前言 回首2024年&a…...
【Linux】网络基础探索:开启你的网络之旅
🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 一:🔥 计算机网络背景 🦋 1-1 网络发展 二:🔥 初识协议 🦋 2-1 协议分层协议分层 vs. 软件分层 🦋 2-…...
function isBulkReadStatement, file SQLiteDatabaseTracking.cpp
一问题:Xcode16.0运行在iPhone16/ios18.0 以上发生闪退, 闪退在 YYCache–>YYKVStorage 文件内。 以上删除保以下错误: function isBulkReadStatement, file SQLiteDatabaseTracking.cpp 解决方案: 找到YYKVStorage文件中_d…...
React 中hooks之useTransition使用总结
目录 概述基本用法使用场景最佳实践注意事项 概述 什么是 useTransition? useTransition 是 React 18 引入的新 Hook,用于标记非紧急的状态更新。它允许组件在状态转换期间保持响应,通过将某些更新标记为"过渡"来推迟它们的渲染。 主要特…...
leetcode 3097. 或值至少为 K 的最短子数组 II 中等
给你一个 非负 整数数组 nums 和一个整数 k 。 如果一个数组中所有元素的按位或运算 OR 的值 至少 为 k ,那么我们称这个数组是 特别的 。 请你返回 nums 中 最短特别非空 子数组 的长度,如果特别子数组不存在,那么返回 -1 。 示例 1&…...
C# OpenCV机器视觉:特征匹配 “灵魂伴侣”
在一个阳光仿佛被施了魔法,欢快得直蹦跶的早晨,阿强像个即将踏上神秘寻宝之旅的探险家,一屁股墩在实验室那张堆满各种奇奇怪怪小玩意儿的桌前。桌上,零件、线路、半成品设备乱成一团,唯有他那宝贝电脑屏幕散发着清冷又…...
DDD - 整洁架构_解决技术设计困局
文章目录 Pre如何落地 DDD底层技术的更迭 整洁架构的设计主动适配器/北向适配器被动适配器/南向适配器 整洁架构的落地总结 Pre DDD - 软件退化原因及案例分析 DDD - 如何运用 DDD 进行软件设计 DDD - 如何运用 DDD 进行数据库设计 DDD - 服务、实体与值对象的两种设计思路…...
金融项目实战 07|Python实现接口自动化——连接数据库和数据清洗、测试报告、持续集成
目录 一、投资模块(投资接口投资业务) 二、连接数据库封装 和 清洗数据 1、连接数据库 2、数据清洗 4、调用 三、批量执行测试用例 并 生成测试报告 四、持续集成 1、代码上传gitee 2、Jenkin持续集成 一、投资模块(投资接口投资业务…...
Ceph与RAID在存储中的协同工作过程
本文将结合架构图,详细讲解Ceph与RAID如何在存储环境中相互配合,共同提供高效且可靠的存储服务。 架构概述 从上图中可以看到,Ceph的架构主要分为四个层次: 客户端和服务接口层:这一层包括客户端访问存储应用的接口…...
《重生到现代之从零开始的C++生活》—— 类和对象2
类的默认成员函数 默认成员函数就是用户没有显示实现,编译器会自动生成的成员函数,一个类会默认生成6个成员函数 构造函数 构造函数时特殊的成员函数,构造函数的初始化对象 函数名与类名相同 没有返回值 对象实例化的时候胡自动调用构造…...
MFC 使用 32位带Alpha通道的位图
最近需要做一个MFC界面上的图片,众所周知,MFC 好像只支持 bmp 格式的! 先看我的原始24位图片,RGB 三个颜色各占8位 (256色), 所以是24位。 如果放到MFC界面上,是这个很丑的效果 它是一个正方形图片,周围的白色可以看见。 解下来,进入今天的主题: 32位带 Alpha 通…...
QT:子控件VLC播放视频时,父控件无法截取鼠标事件
具体来说: 反复验证,结论正确。只要是播放区(即传递给VLC的窗口区域),就无法点击。 比如WidgetA,新建一个WidgetB,设置位置时留有一点边框。这个时候WidgetA的边框区是能收到鼠标事件的。 这…...
力扣 739. 每日温度
🔗 https://leetcode.cn/problems/daily-temperatures 题目 给定一个数组,表示每天的天气返回一个数组,index i 表示几天后比当前的温度要高,没有则为 0 思路 维护一个单调递减栈,若当前的温度比栈顶大,…...
蓝桥杯 阶乘的和(C++完整代码+详细分析)
题目描述 原题链接 阶乘的和 问题描述 给定 n 个数 Ai,问能满足 m! 为 ∑(Ai!) 的因数的最大的 m 是多少。其中 m! 表示 m 的阶乘,即 123⋯m。 输入格式 输入的第一行包含一个整数 n。 第二行包含 n 个整数,分别表示 Ai,相…...
OpenAI进军实体机器人:GPT赋能的智能未来
近年来,人工智能技术飞速发展,深刻地改变着我们的生活。而OpenAI作为人工智能领域的领军者,其最新动作更是引人注目:进军实体机器人领域!这不仅标志着人工智能技术应用场景的重大拓展,也预示着未来智能机器…...
【Python运维】用Python管理Docker容器:从`docker-py`到自动化部署的全面指南
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在现代软件开发和运维过程中,Docker容器化技术因其高效、轻量和可移植性而被广泛应用。Python作为一种灵活且功能强大的编程语言,通过doc…...
【机器学习实战入门项目】MNIST数字分类机器学习项目
Python 深度学习项目:手写数字识别 为了使机器更加智能,开发者们正在深入研究机器学习和深度学习技术。人类通过不断练习和重复来学习执行某项任务,从而记住如何完成这些任务。然后,大脑中的神经元会自动触发,他们能够…...
【统计信号处理基础——估计与检测理论】Vol1.Ch1 引言
文章目录 1. 信号处理中的估计2. 估计的数学问题3. 估计量性能评估习题1.11.21.31.41.5 1. 信号处理中的估计 从离散时间波形或一组数据集中提取参数的问题。我们有 N N N点数据集 { x [ 0 ] , x [ 1 ] , ⋯ , x [ N − 1 ] } \{x[0],x[1],\cdots,x[N-1]\} {x[0],x[1],⋯,x[N−…...
Linux 存储设备和 Ventoy 启动盘制作指南
一、Linux 存储设备基础知识 1. 设备路径(/dev) 设备路径是 Linux 系统中物理存储设备的唯一标识,类似设备的"身份证号"。 命名规则解析 /dev/sda: /dev:device(设备)的缩写&…...
第14章:Python TDD应对货币类开发变化(一)
写在前面 这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许…...
网络协议入门:OSI模型与TCP/IP栈
在网络通信的世界中,数据从一台设备传输到另一台设备,需要遵循一系列规则,这些规则统称为网络协议。OSI模型和TCP/IP协议栈作为网络通信的基石,帮助我们理解数据传输的全流程。这篇文章将深入解析它们的结构、功能和实际应用&…...
pthread_exit函数
pthread_exit 是 POSIX 线程库(pthread)中的一个函数,用于显式地终止调用线程。与 exit 函数不同,pthread_exit 仅影响调用它的线程,而不是整个进程。使用 pthread_exit 可以确保线程在退出时能够正确地释放线程相关的…...
从语音识别到图像识别:AI如何“看”和“听”
引言 随着人工智能技术的不断进步,AI的“听”和“看”能力正变得越来越强大。从语音识别到图像识别,AI不仅能够通过声音与我们互动,还能通过视觉理解和分析周围的世界。这些技术不仅改变了我们与机器的交互方式,也在各行各业中带…...
UML-对象图(Object Diagram)
定义 在UML(统一建模语言)中,对象图用于描述在某一时刻,一组对象以及它们之间关系的图形。它是系统详细状态在某一时刻的快照,常用于表示复杂的类图的一个实例。关联、依赖和继承是对象图中常见的三种关系,下面将对这三种关系进行详细说明,并阐述它们之间的区别。 Pla…...
Pytorch - YOLOv11自定义资料训练
►前言 本篇将讲解目前最新推出的YOLOv11搭配Roboflow进行自定义资料标注训练流程,透过Colab上进行实作说明,使大家能够容易的了解YOLOv11的使用。 ►YOLO框架下载与导入 ►Roboflow的资料收集与标注 进行自定义资料集建置与上传 透过Roboflow工具进行…...
大模型GUI系列论文阅读 DAY2续2:《使用指令微调基础模型的多模态网页导航》
摘要 自主网页导航的进展一直受到以下因素的阻碍: 依赖于数十亿次的探索性交互(通常采用在线强化学习),依赖于特定领域的模型设计,难以利用丰富的跨领域数据进行泛化。 在本研究中,我们探讨了基于视觉-语…...
Docker 搭建mysql 连接超时问题,xxl-job启动mysql连接报错,禁用dns
1.本地连接Navicat报错信息,猜测是navicat默认连接超时导致的,后面换成idea一个插件虽然慢但连接上了 2013 - Lost connection to MySQL server at reading initial communication packet 2.启动xxl-job会报错,网上有人mysql驱动与数据库不匹…...
SSM课设-学生管理系统
【课设者】SSM课设-学生管理系统 技术栈: 后端: SpringSpringMVCMybatisMySQLJSP 前端: HtmlCssJavaScriptEasyUIAjax 功能: 学生端: 登陆 学生信息管理 个人信息管理 老师端: 多了教师信息管理 管理员端: 多了班级信息管理 多了年级信息管理 多了系统用户管理...