cocos单例工厂和自动装配

cocos单例工厂和自动装配

1 单例工厂

1.1 分析
  1. 实例字典

原理很简单,只是一个map,确保每个类只保留一个实例;

private static _instances = new Map<string, any>();
  1. 获取与存储实例

这边使用的方式是生成一个唯一的id存储在类上,获取实例的时候通过这个id值拿到实例对象;

这里很多人会疑惑,为什么不直接使用类名作为标识来记录和获取实例?原因很简单,在项目构建之后类名是随机的、可能重复的;如果还是希望使用类名作为标识,可以参考cocos 3.x@ccclass装饰器的写法,将类名字符串传入。(ccclass源码)

因设计过程中考虑到可能存在需传参的构造器,所以为了强化职责性就不考虑传入类名作为标识了;

public static getInst<T>(classType: { new(...args): T }): T {let key = classType['_singletonId'];if (!key || !this._instances[key]) {console.error("无实例");return null;}return this._instances[key];
}
public static setInst(classType, ...args): void {if(classType._singletonId)return;let key = UUID.generate();while(this._instances[key]) {key = UUID.generate();}this._instances[key] = new classType(...args);classType._singletonId = key;
}
  1. 单例注解(装饰器)

使用方式在需要托管的类上直接添加Singleton即可,如果规范是所有单例都无参可以将返回的函数上移(代码段中可见),标记单例时写法更简洁;

checkIsClass函数用于检测标记的是否为类;

export function Singleton(...args) {return function (target: any) {if (checkIsClass(target)){SingletonFactory.setInst(target, ...args);}}
}
const checkIsClass = function (target: unknown): boolean {return (typeof target === "function" && "prototype" in target && target.prototype.constructor === target);
}
//规范是单例都无参的写法
export function Singleton(target: any) {if (checkIsClass(target)){SingletonFactory.setInst(target, ...args);}
}
//使用方式有参
@Singleton(info)
export default class DataCenter{private info = null;constructor(info) {this.info = info;}
}
//使用方式无参
@Singleton()
export default class EventManager{}
  1. 自动注入

自动注入也是使用的注解方式,标记主动注入的属性所属的类一定要使用单例注解,否则取值为空;

需要注意的是,因为注解的执行时机在创建阶段,而循环依赖的类在使用import时不能立即获得类,故传入的target会出现未定义的状况,故希望使用自动注入的注解时一定要避免循环依赖的出现。存在循环依赖的类只能在使用时通过单例工厂取获取实例;

export function Autowired<T>(constructor: new (...args) => T) {return function (target: any, propertyName) {Object.defineProperty(target, propertyName, {configurable: true,get: function () {return SingletonFactory.getInst(constructor);},set: function(value) {}})}
}
//Autowired使用方式
export default class xxxView {@Autowired(LobbyLogic)lobbyLogic: LobbyLogic = null;
}
//直接使用单例工厂
SingletonFactory.getInst(单例类);
1.3 源码
  1. 单例工厂实现
import UUID from "./UUID";
export default class SingletonFactory {private static _instances = new Map<string, any>();public static getInst<T>(classType: { new(...args): T }): T {let key = classType['_singletonId'];if (!key || !this._instances[key]){console.error("无实例");return null;}return this._instances[key];}static setInst(classType, ...args): void {if(classType._singletonId)return;let key = UUID.generate();while (this._instances[key]) {key = UUID.generate();}this._instances[key] = new classType(...args);classType._singletonId = key;}
}
export function Singleton(...args) {return function (target: any) {if (checkIsClass(target)){SingletonFactory.setInst(target, ...args);}}
}
export function Autowired<T>(constructor: new (...args) => T) {return function (target: any, propertyName) {Object.defineProperty(target, propertyName, {configurable: true,get: function () {return SingletonFactory.getInst(constructor);},set: function(value) {}})}
}
const checkIsClass = function (target: unknown): boolean {return (typeof target === "function" && "prototype" in target && target.prototype.constructor === target);
}
  1. UUID实现
export default class UUID {static generate(): string {const hexDigits = '0123456789abcdef'const s: string[] = Array(36).fill('')for (let i = 0; i < 36; i++) {s[i] = hexDigits.charAt(Math.floor(Math.random() * 0x10))}s[14] = '4's[19] = hexDigits.charAt((parseInt(s[19], 16) & 0x3) | 0x8)s[8] = s[13] = s[18] = s[23] = '-'return s.join('');}
}

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

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

相关文章

django paramiko 跳转登录

在使用Django框架结合Paramiko进行SSH远程操作时&#xff0c;通常涉及到自动化脚本的执行&#xff0c;比如远程服务器上的命令执行、文件传输等。如果你的需求是“跳转登录”&#xff0c;即在登录远程服务器后&#xff0c;再通过该服务器的SSH连接跳转到另一台服务器&#xff0…

《C++初阶之类和对象》【命名空间 + 输入输出 + 缺省参数 + 函数重载】

【命名空间 输入&输出 缺省参数 函数重载】目录 前言&#xff1a;---------------hello world---------------比较C语言和C的第一个程序&#xff1a;hello word ---------------命名空间---------------什么是命名空间&#xff1f;怎么使用命名空间&#xff1f;怎么定义…

[USACO1.5] 八皇后 Checker Challenge Java

import java.util.*;public class Main {// 标记 对角线1&#xff0c;对角线2&#xff0c;所在x轴 是否存在棋子static boolean[] d1 new boolean[100], d2 new boolean[100], d new boolean[100]; static int n, ans 0;static int[] arr new int[14]; // 记录一轮棋子位置…

云服务器Xshell登录拒绝访问排查

根据你的描述&#xff0c;使用Xshell 8登录云服务器时显示“拒绝访问”&#xff0c;可能涉及多个原因。以下结合搜索结果整理出排查和解决方法&#xff0c;按优先级排序&#xff1a; 一、检查基础网络与端口连通性 本地网络与服务器IP是否可达 在本地电脑的CMD中执行 ping 服务…

Python爬虫实战:研究urlunparse函数相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上的数据量呈现出指数级增长。如何从海量的网页数据中高效地获取有价值的信息,成为了学术界和工业界共同关注的问题。网络爬虫作为一种自动获取网页内容的技术,能够按照预定的规则遍历互联网上的网页,并提取出所需…

Spring AI学习一

随着Chatpt的火爆&#xff0c;现在Spring官方也开始支持AI了并推出了Spring AI框架&#xff0c;目前还没发布正式版本&#xff0c;这里可以先看一下官方依赖的版本。 Spring官网地址可以看这里&#xff1a;Spring | Home 目前官网上是有这两个版本&#xff1a;1.0.0和1.1.0-SN…

reverse笔记

一&#xff0c;strcat的使用方法&#xff08;在攻防世界中刷题时遇到的&#xff09; 二&#xff0c;壳&#xff08;做题遇到过但是一直不是很理解&#xff0c;今天查了一下&#xff09; 壳是一种软件保护技术&#xff0c;能够防止程序被轻易地分析和修改。 总而言之&#xff0…

spring4第7-8课-AOP的5种通知类型+切点定义详解+执行顺序

继续学习&#xff0c;方便自己复查记录 ①AOP简介&#xff1a; 面向切面编程(也叫面向方面编程)&#xff1a;Aspect Oriented Programming(AOP)。 Spring框架中的一个重要内容。。 通过预编译方式和运行期间动态代理实现在不修改源代码的情况下给程序动态统一添加功能…

EscapeX:去中心化游戏,开启极限娱乐新体验

VEX 平台推出全新去中心化游戏 EscapeX&#xff08;数字逃脫&#xff09;&#xff0c;创新性地将大逃杀玩法与区块链技术相融合。用户不仅能畅享紧张刺激的解谜过程&#xff0c;更能在去中心化、公正透明的环境中参与游戏。EscapeX 的上线&#xff0c;为 VEX 生态注入全新活力&…

Multi Agents Collaboration OS:Web DeepSearch System

背景&#xff1a;多智能体协作驱动网络信息处理的范式革新 随着大型语言模型&#xff08;LLM&#xff09;能力的突破性进展&#xff0c;人工智能正从“单点赋能”向“系统协同”演进。传统单一智能体在复杂业务场景中逐渐显露局限&#xff1a;面对需多维度知识整合、动态任务拆…

React 第五十三节 Router中 useRouteError 的使用详解和案例分析

前言 useRouteError 是 React Router v6.4 引入的关键错误处理钩子&#xff0c;用于在 路由错误边界&#xff08;Error Boundary&#xff09; 中获取路由操作过程中发生的错误信息。 它提供了优雅的错误处理机制&#xff0c;让开发者能够创建用户友好的错误界面。 一、useRou…

[arthas]arthas安装使用

arthas是阿里开源的一个java线上监控以及诊断工具&#xff0c;在docker容器中我们无需重启服务&#xff0c;也不用更改代码&#xff0c;就可以完成对应用内存、线程、日志级别的修改、方法调用的出入参、异常监测、执行耗时等&#xff0c;xxxx.xxxx.xxxxx为脱敏内容 1. 在docke…

Flask-Babel 使用示例

下面创建一个简单的 Flask-Babel 示例&#xff0c;展示如何在 Flask 应用中实现国际化和本地化功能。这个示例将包括多语言支持&#xff08;中文和英文&#xff09;、语言切换功能以及翻译文本的使用。 项目结构 我们将创建以下文件结构&#xff1a; 1. 首先&#xff0c;创…

[论文阅读] 软件工程 | 量子计算如何赋能软件工程(Quantum-Based Software Engineering)

arXiv:2505.23674 [pdf, html, other] Quantum-Based Software Engineering Jianjun Zhao Subjects: Software Engineering (cs.SE); Quantum Physics (quant-ph) 量子计算如何赋能软件工程 我们在开发软件时&#xff0c;常常会遇到一些棘手的问题。比如&#xff0c;为了确保软…

Ansible 进阶 - Roles 与 Inventory 的高效组织

Ansible 进阶 - Roles 与 Inventory 的高效组织 如果说 Playbook 是一份完整的“菜谱”,那么 Role (角色) 就可以被看作是制作这道菜(或一桌菜)所需的标准化“备料包”或“半成品组件”。例如,我们可以有一个“Nginx Web 服务器安装配置 Role”、“MySQL 数据库基础设置 Ro…

青少年编程与数学 01-011 系统软件简介 04 Linux操作系统

青少年编程与数学 01-011 系统软件简介 04 Linux操作系统 一、Linux 的发展历程&#xff08;一&#xff09;起源&#xff08;二&#xff09;早期发展&#xff08;三&#xff09;成熟与普及&#xff08;四&#xff09;移动与嵌入式领域的拓展 二、Linux 的内核与架构&#xff08…

将图形可视化工具的 Python 脚本打包为 Windows 应用程序

前文我们已经写了一个基于python的tkinter库和matplotlib库的图形可视化工具。 基于Python的tkinter库的图形可视化工具&#xff08;15种图形的完整代码&#xff09;:基于Python的tkinter库的图形可视化工具&#xff08;15种图形的完整代码&#xff09;-CSDN博客 在前文基础上&…

【Kotlin】简介变量类接口

【Kotlin】简介&变量&类&接口 【Kotlin】数字&字符串&数组&集合 【Kotlin】高阶函数&Lambda&内联函数 【Kotlin】表达式&关键字 文章目录 Kotlin_简介&变量&类&接口Kotlin的特性Kotlin优势创建Kotlin项目变量变量保存了指向对…

OpenCV种的cv::Mat与Qt种的QImage类型相互转换

一、首先了解cv::Mat结构体 cv::Mat::step与QImage转换有着较大的关系。 step的几个类别区分: step:矩阵第一行元素的字节数step[0]:矩阵第一行元素的字节数step[1]:矩阵中一个元素的字节数step1(0):矩阵中一行有几个通道数step1(1):一个元素有几个通道数(channel()) cv::Ma…

搭建基于VsCode的ESP32的开发环境教程

一、VsCode搜索ESP-IDF插件 根据插件处搜索找到ESP-IDF并安装 安装完成 二、配置安装ESP-IDF 配置IDF 按照如下配置&#xff0c;点击安装 安装完成 三、使用案例程序 创建一个闪光灯的例子程序&#xff0c;演示程序编译下载。 选择blink例子&#xff0c;闪烁LED的程序 选…