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

PureMVC在Unity中的使用(含下载链接)

前言

        Pure MVC是在基于模型、视图和控制器MVC模式建立的一个轻量级的应用框架,这种开源框架是免费的,它最初是执行的ActionScript 3语言使用的Adobe Flex、Flash和AIR,已经移植到几乎所有主要的发展平台,支持两个版本框架:标准和多核,总之,标准版提供了一种简单的编码分离的方法,按照MVC设计概念。

        官方网址:http://puremvc.org/

        下载链接(c#):https://codeload.github.com/PureMVC/puremvc-csharp-standard-framework/zip/refs/heads/master

        官方文档:进入网站后一直下滑,找到China国旗,点击Read PDF既能看到官方的中文PDF文档。

其基本结构为MVC加上常用的设计模式

  • Model(数据模型):关联Proxy(代理)对象,负责处理数据。
  • View(界面):关联Mediator(中介)对象,负责处理界面。
  • Controller(业务控制):管理Command(命令)对象,负责处理业务逻辑。
  • Facade(外观):是MVC三者的经纪人,统管全局,可以获取代理、中介、命令。
  • Notification :通知,负责传递信息。

 导入Unity

Pure MVC导入到Unity中有两种方式:

第一种方法

先打开工程文件

在解决方案处点击生成 

在puremvc-csharp-standard-framework-master\PureMVC\bin\Debug\net5.0这个路径 复制dll文件到Unity的Plugins文件里

第二种方法

在puremvc-csharp-standard-framework-master\PureMVC路径直接复制这三个文件到Unity里

PureMVC思想

Model

        Model在PureMVC中主要负责保存对Proxy对象的引用,并通过这些Proxy对象来操作数据模型,以及与远程服务进行通信以存取数据。Model是MVC架构中的核心部分之一,它负责管理和维护应用程序的数据状态。

Proxy的作用

        Proxy在PureMVC中充当数据模型和应用程序其他部分之间的中介。它提供了一个包装器或中介,使客户端能够方便地访问和操作场景背后的真实对象。Proxy可以管理数据对象(Data Object)以及对数据对象的访问,包括数据的查询、插入、更新和删除等操作。

Obj(Data Objects)类

/// <summary>
/// 玩家数据结构
/// </summary>
public class PlayerDataObj
{//申明一堆玩家属性相关的变量public string playerName;public int lev;public int money;public int gem;public int power;public int hp;public int atk;public int def;public int crit;public int miss;public int luck;
}

Proxy(代理)类

using PureMVC.Patterns.Proxy;
using UnityEngine;/// <summary>
/// 玩家数据代理对象
/// 主要处理 玩家数据更新相关的逻辑
/// </summary>
public class PlayerProxy : Proxy
{//1.继承Proxy父类//2.写构造函数public new const string NAME = "PlayerProxy";public PlayerProxy() : base(PlayerProxy.NAME){//在构造函数中 初始化一个数据 进行关联PlayerDataObj data = new PlayerDataObj();//初始化data.playerName = PlayerPrefs.GetString("PlayerName","玩家01");data.lev = PlayerPrefs.GetInt("PlayerLev", 1);data.money = PlayerPrefs.GetInt("PlayerMoney",9999);data.gem = PlayerPrefs.GetInt("PlayerGem",8888);data.power = PlayerPrefs.GetInt("PlayerPower",99);data.hp = PlayerPrefs.GetInt("PlayerHp", 100);data.atk = PlayerPrefs.GetInt("PlayerAtk", 20);data.def = PlayerPrefs.GetInt("PlayerDef", 10);data.crit = PlayerPrefs.GetInt("PlayerCrit", 20);data.miss = PlayerPrefs.GetInt("PlayerMiss", 10);data.luck = PlayerPrefs.GetInt("PlayerLuck", 40);//赋值给自己的Data进行关联Data = data;}public void LevUp(){PlayerDataObj data = Data as PlayerDataObj;//升级 改变内容data.lev += 1;data.hp += data.lev;data.atk += data.lev;data.def += data.lev;data.crit += data.lev;data.miss += data.lev;data.luck += data.lev;}public void SaveDate(){PlayerDataObj data = Data as PlayerDataObj;//将数据存储到本地PlayerPrefs.SetString("PlayerName",data.playerName);PlayerPrefs.SetInt("PlayerLev",data.lev);PlayerPrefs.SetInt("PlayerMoney",data.money);PlayerPrefs.SetInt("PlayerGem",data.gem);PlayerPrefs.SetInt("PlayerPower",data.power);PlayerPrefs.SetInt("PlayerHp",data.hp);PlayerPrefs.SetInt("PlayerAtk",data.atk);PlayerPrefs.SetInt("PlayerDef",data.def);PlayerPrefs.SetInt("PlayerCrit",data.crit);PlayerPrefs.SetInt("PlayerMiss",data.miss);PlayerPrefs.SetInt("PlayerLuck",data.luck);}}

View

Mediator的作用

        一个Mediator通常关联着多个UI组件,负责它们的创建、更新和销毁等生命周期管理。Mediator可以监听来自UI组件的事件,并将这些事件转发给PureMVC框架中的其他部分(如Command或Proxy),同时也可以接收来自其他部分的通知,并据此更新UI组件。

UI(View Components类)

主面板

using UnityEngine;
using UnityEngine.UI;public class MainView : MonoBehaviour
{//1.寻找控件public Button btnRole;public Button btnSill;public Text txtName;public Text txtLev;public Text txtMoney;public Text txtGem;public Text txtPower;//2.提供面板更新的相关方法给外部public void UpdateInfo(PlayerDataObj data){txtName.text =data.playerName;txtLev.text = "LV." + data.lev;txtMoney.text = data.money.ToString();txtGem.text = data.gem.ToString();txtPower.text = data.power.ToString();}
}

角色面板

using UnityEngine;
using UnityEngine.UI;public class RoleView : MonoBehaviour
{//1.寻找控件public Button btnClose;public Button btnLevUp;public Text txtLev;public Text txtHp;public Text txtAtk;public Text txtDef;public Text txtCrit;public Text txtMiss;public Text txtLuck;//2.提供面板更新的相关方法给外部public void UpdateInfo(PlayerDataObj data){txtLev.text = "Lv."+ data.lev;txtHp.text = data.hp.ToString();txtAtk.text = data.atk.ToString();txtDef.text = data.def.ToString();txtCrit.text = data.crit.ToString();txtMiss.text = data.miss.ToString();txtLuck.text = data.luck.ToString();}
}

Mediator(中介者)类

主面板管理

using PureMVC.Interfaces;
using PureMVC.Patterns.Mediator;public class MainViewMediator : Mediator
{public static new string NAME = "MainViewMediator";//套路写法//1.继承PureMVC中的Meditor脚本//2.写构造函数public MainViewMediator() : base(NAME){//这里写创建界面预设体等等的逻辑//但是界面显示应该是触发的控制的//而且创建界面的代码 重复性比较高}//3.重写监听通知方法public override string[] ListNotificationInterests(){//PureMVC的规则//需要监听哪些通知 就在这里将通知们通过字符串数组的形式返回出去//PureMVC就会帮助我们监听这些通知(类似于通过事件名 注册事件监听)return new string[] {PureNotification.UPDATE_PLAYE_INFO,};}//4.重写处理通知方法public override void HandleNotification(INotification notification){//INotification 对象 里面包含两个对我们来说非常重要的参数//(1).通知名 我们根据这个名字 来做对应的处理//(2).通知包含的信息switch(notification.Name){case PureNotification.UPDATE_PLAYE_INFO://收到 更新通知的时候 做处理if(ViewComponent !=null){(ViewComponent as MainView).UpdateInfo(notification.Body as PlayerDataObj);}break;}}//5.可选:重写注册时的方法public override void OnRegister(){base.OnRegister();//初始化一些内容}public void SetView(MainView view){ViewComponent = view;view.btnRole.onClick.AddListener(() =>{//继承了Mediator,Command,Proxy的类可以直接使用发送通知的方法SendNotification(PureNotification.SHOW_PANEL, "RolePanel");});}
}

角色面板管理

using PureMVC.Interfaces;
using PureMVC.Patterns.Mediator;public class RoleViewMediator : Mediator
{public static new string NAME = "MainViewMediator";//1.继承PureMVC中的Mediator脚本//2.写构造函数public RoleViewMediator() : base(NAME){}//3.重写监听通知的方法public override string[] ListNotificationInterests(){//PureMVC的规则//需要监听哪些通知 就在这里将通知们通过字符串数组的形式返回出去//PureMVC就会帮助我们监听这些通知(类似于通过事件名 注册事件监听)return new string[] {PureNotification.UPDATE_PLAYE_INFO,//关心别的通知 就在这后面通过逗号加起来连接};}//4.重写处理通知的方法public override void HandleNotification(INotification notification){//INotification 对象 里面包含两个对我们来说 重要的参数//1:通知名 根据这个名字来做对应的处理//2.通知包含的信息switch (notification.Name){case PureNotification.UPDATE_PLAYE_INFO://玩家数据更新 逻辑处理if(ViewComponent != null ){(ViewComponent as RoleView).UpdateInfo(notification.Body as PlayerDataObj);}break;}}public void SetView(RoleView view){ViewComponent = view;//关闭按钮事件监听view.btnClose.onClick.AddListener(() =>{//继承了Mediator,Command,Proxy的类可以直接使用发送通知的方法SendNotification(PureNotification.HIDE_PANEL, this);});//升级按钮监听view.btnLevUp.onClick.AddListener(() =>{//升级//通知升级SendNotification(PureNotification.LEV_UP);});}
}

Facade

        Facade为PureMVC中的Model、View和Controller提供了一个统一的访问接口。开发者不需要直接访问这些子系统的具体实现,只需要通过Facade即可。Facade通常被实现为单例模式,以确保整个系统中只有一个Facade实例。

using PureMVC.Patterns.Facade;public class GameFacade : Facade
{//1.继承PureMVC中Facade脚本//2.为了方便我们使用Facade 学要自己写一个单例模式的属性public static GameFacade Instance{get{if(instance==null){instance = new GameFacade();}return instance as GameFacade;}}//3.初始化控制层相关的内容protected override void InitializeController(){base.InitializeController();//这里写一些 关于命令和通知绑定的逻辑//注册初始化命令RegisterCommand(PureNotification.START_UP,()=>{return new StartUpCommand();//当发送START_UP命令时返回一个StartUpCommand()命令并自动执行Excute方法});//注册显示面板命令RegisterCommand(PureNotification.SHOW_PANEL, () =>{return new ShowPanelCommand();});//注册隐藏面板命令RegisterCommand(PureNotification.HIDE_PANEL, () =>{return new HidePanelCommand();});//注册玩家升级命令RegisterCommand(PureNotification.LEV_UP, () =>{return new LevUpCommand();});}//4.启动函数public void StartUp(){//发送通知//(1)第一个参数为想要执行的命令//(2)第二个参数为传入的参数string类型的notification.BodySendNotification(PureNotification.START_UP);//这里是真正开始执行命令的逻辑//SendNotification(PureNotification.SHOW_PANEL,"MainPanel");}
}

Controller

        Controller是PureMVC框架中的消息处理中心,它接收来自View的通知(Notification),并根据通知的类型调用相应的Command来执行特定的业务逻辑。

        在PureMVC中,Command通过注册到Facade上,可以接收来自View或Model的通知。这些通知通常包含了触发事件的相关信息。当Command接收到通知后,它会根据通知的类型和携带的信息,执行相应的业务逻辑。

PureMVC通知类

/// <summary>
/// 这个是pureMVC中的 通知类
/// 主要是用来申明各个通知的 名字
/// 方便使用和管理
/// </summary>
public class PureNotification
{//启动通知public const string START_UP = "startUp";//显示面板通知public const string SHOW_PANEL = "showPanel";//隐藏面板通知public const string HIDE_PANEL = "hidePanel";//代表玩家数据更新的通知名public const string UPDATE_PLAYE_INFO = "updatePlayerInfo";//玩家升级通知public const string LEV_UP = "levUp";
}

初始化命令

using PureMVC.Interfaces;
using PureMVC.Patterns.Command;
public class StartUpCommand : SimpleCommand
{//1.继承Command相关的脚本//2.重写里面的执行函数public override void Execute(INotification notification){base.Execute(notification);//当命令被执行时 就会调用该方法//启动命令中往往是做一些初始化操作//没有这个数据代理 才注册 有了就别注册if(!Facade.HasProxy(PlayerProxy.NAME)){Facade.RegisterProxy(new PlayerProxy());}}
}

显示面板命令

using PureMVC.Interfaces;
using PureMVC.Patterns.Command;
using UnityEngine;
public class ShowPanelCommand : SimpleCommand
{public override void Execute(INotification notification){base.Execute(notification);//写面板创建的逻辑string panelName = notification.Body.ToString();switch(panelName){case "MainPanel"://显示主面板相关内容//如果要使用Mediator 一定也要在Facade中去注册//commend、proxy都是一样的 想要使用 就要注册//可以在命令中直接使用Facade代表的就是唯一的Facadeif(!Facade.HasMediator(MainViewMediator.NAME))//判断Facade里面有没有Mediator,没有就实例化一个,防止Mediator重复{Facade.RegisterMediator(new MainViewMediator());//新建一个Mediator对象,将它传入Facade里面注册}//Facade 得到Mediator的方法MainViewMediator mainMe = Facade.RetrieveMediator(MainViewMediator.NAME) as MainViewMediator;//有了Mediator之后创建界面 预设体if(mainMe.ViewComponent == null){//实例化面板GameObject res = Resources.Load<GameObject>("UI/MainPanel");GameObject obj = GameObject.Instantiate(res);//设置它的父对象 为Canvansobj.transform.SetParent(GameObject.Find("Canvas").transform, false);//得到预设体上的 view脚本 关联到mediator上mainMe.SetView(obj.GetComponent<MainView>());}//实现面板后在这里进行更新//需要把数据通过参数传出去SendNotification(PureNotification.UPDATE_PLAYE_INFO,Facade.RetrieveProxy(PlayerProxy.NAME).Data);break;case "RolePanel"://显示角色面板相关内容if (!Facade.HasMediator(MainViewMediator.NAME)){Facade.RegisterMediator(new MainViewMediator());}RoleViewMediator roleMe = Facade.RetrieveMediator(MainViewMediator.NAME) as RoleViewMediator;if (roleMe.ViewComponent == null){GameObject res = Resources.Load<GameObject>("UI/RolePanel");GameObject obj = GameObject.Instantiate(res);obj.transform.SetParent(GameObject.Find("Canvas").transform, false);roleMe.SetView(obj.GetComponent<RoleView>());}SendNotification(PureNotification.UPDATE_PLAYE_INFO, Facade.RetrieveProxy(PlayerProxy.NAME).Data);break;}}
}

隐藏面板命令

using PureMVC.Interfaces;
using PureMVC.Patterns.Command;
using PureMVC.Patterns.Mediator;
using UnityEngine;public class HidePanelCommand : SimpleCommand
{public override void Execute(INotification notification){base.Execute(notification);//隐藏的目的//得到mediator 在得到mediator 中的 view 然后去要不删除 要不 设置显隐//得到传入的 mediatorMediator m =notification.Body as Mediator;if (m!=null && m.ViewComponent != null){//直接删除场景上的面板对象GameObject.Destroy((m.ViewComponent as MonoBehaviour).gameObject);//删除后置空m.ViewComponent = null;}}
}

升级数据命令

using PureMVC.Interfaces;
using PureMVC.Patterns.Command;public class LevUpCommand : SimpleCommand
{public override void Execute(INotification notification){base.Execute(notification);//得到数据代理 调用升级 升级完成后通知别人 更新数据PlayerProxy playerProxy =Facade.RetrieveProxy(PlayerProxy.NAME) as PlayerProxy;if(playerProxy != null){//升级playerProxy.LevUp();//保存数据//playerProxy.SaveDate();//通知更新SendNotification(PureNotification.UPDATE_PLAYE_INFO,playerProxy.Data);}}
}

总结

        在PureMVC中,通常遵循一种特定的开发流程或“套路”来构建应用程序。这个流程大致可以概括为:先定义Model数据,再设计View界面,然后使用Command命令进行模块间的串联,最后通过Facade类进行模块的判断、注册和获取。

相关文章:

PureMVC在Unity中的使用(含下载链接)

前言 Pure MVC是在基于模型、视图和控制器MVC模式建立的一个轻量级的应用框架&#xff0c;这种开源框架是免费的&#xff0c;它最初是执行的ActionScript 3语言使用的Adobe Flex、Flash和AIR&#xff0c;已经移植到几乎所有主要的发展平台&#xff0c;支持两个版本框架&#xf…...

25国考照片处理器使用流程图解❗

1、打开“国家公务员局”网站&#xff0c;进入2025公务员专题&#xff0c;找到考生考务入口 2、点击下载地址 3、这几个下载链接都可以 4、下载压缩包 5、解压后先看“使用说明”&#xff0c;再找到“照片处理工具”双击。 6、双击后会进入这样的界面&#xff0c;点击&…...

一位纯理科生,跨界自学中医,自行组方治好胃病、颈椎病与高血脂症,并在最权威的中国中医药出版社出版壹本专业中医图书!

这是一位铁杆中医迷&#xff0c; 也是《神农本草经——精注易读本》的作者。 希望更多的人能够受到启发&#xff0c;感受中医之神奇&#xff0c;敢于跨界&#xff0c;爱好中医&#xff0c;学习中医&#xff01; 一个病人以自己的切身感受与诊断&#xff0c;并使之汤药治愈疾病&…...

运动控制 双轮差速模型轨迹规划

文章目录 一、轨迹规划1.1轨迹平滑与轮迹1.2 目标距离1.3 速度限制1.4 候选速度的计算与调整1.5 路径生成 二、双轮轨迹2.1 计算梯度2.2 计算偏移轨迹2.3 返回结果 一、轨迹规划 1.1轨迹平滑与轮迹 初始时&#xff0c;我们有一条由若干坐标点构成的机器人运行路径。通过对这些…...

使用 Sortable.js 库 实现 Vue3 elementPlus 的 el-table 拖拽排序

文章目录 实现效果Sortable.js介绍下载依赖添加类名导入sortablejs初始化拖拽实例拖拽完成后的处理总结 在开发过程中&#xff0c;我们经常需要处理表格数据&#xff0c;并为用户提供便捷的排序方式。特别是在需要管理长列表、分类数据或动态内容时&#xff0c;拖拽排序功能显得…...

MySQL索引相关介绍及优化(未完...)

如何看一条SQL语句的执行好坏&#xff1f; MySQL提供了自带的工具Explain可以查看sql语句的执行好坏。 explain主要的列&#xff1a; 1&#xff1a;type&#xff1a;这一列表示MySQL决定如何查找表中的行&#xff0c;查找数据行记录的大概范围。 有 system const eq_ref ref…...

【AI+教育】一些记录@2024.11.04

一、尝新 今天尝试了使用九章随时问&#xff0c;起因是看到快刀青衣的AI产品好用榜&#xff0c;里面这么介绍九章随时问&#xff1a;「它不是像其他产品那样&#xff0c;直接给你出答案。而是跟你语音对话&#xff0c;你会感觉更像是有一位老师坐在你的旁边&#xff0c;一步步…...

三维测量与建模笔记 - 2.2 射影几何

教程中H矩阵写的有问题&#xff0c;上图中H矩阵应该是&#xff08;n1) x (m1) 共点不变性,下图中黄色方块标记的点&#xff0c;在射影变换前后&#xff0c;虽然直线的形状有所变化&#xff0c;但仍然相交于同一个点。 共线不变性&#xff0c;下图黄色标记的两个点&#xff0c;在…...

论文速读:简化目标检测的无源域适应-有效的自我训练策略和性能洞察(ECCV2024)

中文标题&#xff1a;简化目标检测的无源域适应&#xff1a;有效的自我训练策略和性能洞察 原文标题&#xff1a;Simplifying Source-Free Domain Adaptation for Object Detection: Effective Self-Training Strategies and Performance Insights 1、Abstract 本文重点关注计算…...

ros与mqtt相互转换

vda5050 VDA5050协议介绍 和 详细翻译-CSDN博客 ros与mqtt相互转换 如何转换的&#xff0c;通过某个中转包&#xff0c;获取ros的消息然后以需要的格式转换为mqtt 需要的参数 ros相关 parameters[ (ros_subscriber_type, vda5050_msgs/NodeState), (ros_subscriber_queue…...

Golang | Leetcode Golang题解之第522题最长特殊序列II

题目&#xff1a; 题解&#xff1a; func isSubseq(s, t string) bool {ptS : 0for ptT : range t {if s[ptS] t[ptT] {if ptS; ptS len(s) {return true}}}return false }func findLUSlength(strs []string) int {ans : -1 next:for i, s : range strs {for j, t : range s…...

安卓开发之数据库的创建与删除

目录 前言&#xff1a;基础夯实&#xff1a;数据库的创建数据库的删除注意事项 效果展示&#xff1a;遇到问题&#xff1a;如何在虚拟机里面找到这个文件首先&#xff0c;找到虚拟机文件的位置其次&#xff0c;找到数据库文件的位置 核心代码&#xff1a; 前言&#xff1a; 安…...

数据结构:LRUCache

什么是LRUCache 首先我们来看看什么是cache 缓存&#xff08;Cache&#xff09;通常用于两个速度不同的介质之间&#xff0c;以提高数据访问的速度和效率。这里有几个典型的应用场景&#xff1a; 处理器和内存之间&#xff1a; 处理器&#xff08;CPU&#xff09;的运算速度远…...

shell脚本案例:创建用户和组

使用场景 在部署程序时&#xff0c;往往首要任务是创建用户和组。有的程序可能用到的组、用户比较多&#xff1b;且不知道服务器环境是否已经有了所需的组和用户。所以针对这个情况&#xff0c;根据Oracle RAC部署时的实际情况写了个脚本。 Linux版本 脚本代码 #!/bin/bash …...

C++笔试题之实现一个定时器

一.定时器&#xff08;timer&#xff09;的需求 1.执行定时任务的时&#xff0c;主线程不阻塞&#xff0c;所以timer必须至少持有一个线程用于执行定时任务 2.考虑到timer线程资源的合理利用&#xff0c;一个timer需要能够管理多个定时任务&#xff0c;所以timer要支持增删任务…...

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-13

文件下载与邀请翻译者 学习英特尔开发手册&#xff0c;最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册&#xff0c;会是一件耗时费力的工作。如果有愿意和我一起来做这件事的&#xff0c;那么&#xff…...

快消零售行业的培训创新:构建在线培训知识库

在快速消费品&#xff08;FMCG&#xff09;行业中&#xff0c;员工的培训和发展对于保持竞争力至关重要。随着电子商务的兴起和消费者行为的变化&#xff0c;快消零售行业需要不断适应新的市场趋势。在线培训知识库作为一种有效的培训工具&#xff0c;可以帮助企业提升员工技能…...

【AI开源项目】Botpress - 开源智能聊天机器人平台及其部署方案

文章目录 Botpress 概述Botpress 的定位 Botpress 的主要特点1. OpenAI 集成2. 易于使用3. 定制和扩展性4. 多平台支持5. 集成和扩展 API6. 活跃的社区和详尽的文档 部署方案集成集成开发集成部署机器人示例开发工具代理本地开发先决条件从源代码构建 Botpress 如何解决常见问题…...

一文读懂系列:SSL加密流量检测技术详解

SSL加密流量检测功能的主要目的是为了对加密流量做解密处理&#xff0c;并对解密后的流量做内容安全检查&#xff08;比如反病毒、入侵防御、URL远程查询、内容过滤、文件过滤和邮件过滤等&#xff09;和审计&#xff08;防止信息泄露&#xff09;。接下来我们详细介绍SSL加密流…...

Android Studio各种历史版本

下载地址&#xff1a;AndroidDevTools - Android开发工具 Android SDK下载 Android Studio下载 Gradle下载 SDK Tools下载...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...