游戏设计模式
单列模式
概念
单例模式是一种创建型设计模式,可以保证一个类只有一个实例,并提供一个访问该实例的全局节点。
优点
- 可以派生:在单例类的实例构造函数中可以设置以允许子类派生。
- 受控访问:因为单例类封装他的唯一实例,所以它可以严格的控制其他程序怎样以及何时访问它。
- 可以获得一个指向该实例的全局访问节点。
- 仅在首次请求单例对象时对其进行初始化。
缺点
- 违反了单一职责原则。
- 单例模式一般不要支持序列化,因为这也有可能导致多个对象实例。
- 多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。
组成
1.单例(Singleton)类声明了一个名为getInstance的静态方法来返回其所属类的一个相同实例。
2.单例的构造函数必须私有化,即对客户端(Client)隐藏。调用getInstance方法必须是获取单例对象的唯一方式。
案例
方式1
public class Singleton
{private Singleton() { }private static Singleton instance;public static Singleton GetInstance{get{if (instance == null){instance = new Singleton();}return instance;}}
}
方式2:多线程单例
class SingletonThread
{private SingletonThread() { } //私有化构造private static volatile SingletonThread instance;private static object lockHelper = new Object { };public static SingletonThread GetInstance{get{// 双重校验,为避免额外的性能消耗。if (instance == null){// 当第一个线程运行到这里时,此时会对lock加锁。// 当第二个线程运行该方法时,首先检测到lock加锁状态,该线程就会挂起等待第一个线程解锁。lock (lockHelper){if (instance == null){instance = new SingletonThread();}}}return instance;}}
}
方式3
class SingletonRead
{private SingletonRead() { }//只要访问就会被执行静态构造器,不使用不会进行实例化public static readonly SingletonRead Instance = new SingletonRead();//等价于//public static readonly SingletonRead Instance;//static SingletonRead ()//{// Instance = new SingletonRead ();//}
}
MVC模式
概念
MVC设计模式一般指MVC框架,M(Model)指数据模型层,V(View)指视图层,C(Controller)指控制层。其设计目的是将M和V的实现代码分离,使同一个程序可以有不同的表现形式。
优点
- 多视图共享一个模型,大大提高了代码的重用性。
- MVC三个模块相互独立,松耦合架构。
- 控制器提高了应用程序的灵活性和可配置性。
- 有利于软件工程化管理。
总之,我们通过MVC设计模式最终可以打造出一个松耦合+高可重用性+高可适用性的完美架构。
缺点
- 原理复杂。
- 增加了系统结构和实现的复杂性。
- 视图对模型数据的低效率访问。
MVC并不适合小型甚至中型规模的项目,花费大量时间将MVC应用到规模并不是很大的应用程序,通常得不偿失,所以对于MVC设计模式的使用要根据具体的应用场景来决定。
组成
- 视图层(View):负责格式化数据并把它们呈现给用户,包括数据展示、用户交互、数据验证、界面设计等功能。
- 控制层(Controller):负责接收并转发请求,对请求进行处理后,指定视图并将响应结果发送给客户端。
- 数据模型层(Model):模型对象拥有最多的处理任务,是应用程序的主体部分,它负责数据逻辑(业务规则)的处理和实现数据操作(即在数据库中存取数据)。
案例
新建StudentView.cs、StudentModel.cs和StudentController.cs,分别作为视图层、数据模型层和控制层。
StudentView.cs
using UnityEngine;public class StudentView
{public void PrintStudentDetails(string studentName, string studentRollNo){Debug.Log("Student: ");Debug.Log("Name: " + studentName);Debug.Log("Roll No: " + studentRollNo);}
}
StudentModel.cs
public class StudentModel
{private string name;private string rollNo;public string Name { get => name; set => name = value; }public string RollNo { get => rollNo; set => rollNo = value; }
}
StudentController.cs
public class StudentController
{private StudentModel model;private StudentView view;public StudentController(StudentModel model, StudentView view){this.model = model;this.view = view;}public void SetStudentName(string name){model.Name = name;}public string GetStudentName(){return model.Name;}public void SetStudentRollNo(string rollNo){model.RollNo = rollNo;}public string GetStudentRollNo(){return model.RollNo;}public void UpdateView(){view.PrintStudentDetails(model.Name, model.RollNo);}
}
新建MVCPatternDemo.cs,实现代码如下:
using UnityEngine;public class MVCPatternDemo : MonoBehaviour
{private void Awake(){StudentModel model = RetrieveStudentFromDatabase();StudentView view = new StudentView();//创建一个视图:把学生详细信息输出到控制台StudentController controller = new StudentController(model, view);controller.UpdateView();controller.SetStudentName("John");//更新模型数据controller.UpdateView();}private static StudentModel RetrieveStudentFromDatabase(){StudentModel student = new StudentModel();student.Name = "Robert";student.RollNo = "10";return student;}
}
输出如下:
观察者模式
概念
观察者模式(发布-订阅模式)属于行为型模式。在程序设计中,观察者模式通常由两个对象组成:观察者和被观察者。当被观察者状态发生改变时,它会通知所有的观察者对象,使他们能够及时做出响应。
优点
解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变化都不会影响另一边的变化。
缺点
在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
组成
- 抽象被观察者(Subject):定义了一个接口,包含了注册观察者、删除观察者、通知观察者等方法。
- 具体被观察者(ConcreteSubject):实现了抽象被观察者接口,维护了一个观察者列表,并在状态发生改变时通知所有注册的观察者。
- 抽象观察者(Observer):定义了一个接口,包含了更新状态的方法。
- 具体观察者(ConcreteObserver):实现了抽象观察者接口,存储了需要观察的被观察者对象,并在被观察者状态发生改变时进行相应的处理。
过程
1.观察者(Observer):
观察者将自己注册到被观察者中,被观察者将观察者存放在一个容器里。
2.被观察(Subject):
被观察者发生变化时,从容器中得到所有注册过的观察者,将变化通知观察者。
3.撤销观察
观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现,这一点为程序提供了更大的灵活性。
案例
新建ISubject.cs和IObserver.cs,分别作为抽象被观察者和抽象观察者。
新建ConcreteSubject.cs和ConcreteObserver.cs,分别作为具体被观察者和具体观察者。
脚本内容如下:
ISubject.cs
/// <summary>
/// 抽象被观察者
/// </summary>
public interface ISubject
{/// <summary>/// 添加观察者/// </summary>/// <param name="observer"></param>void AddObserver(IObserver observer);/// <summary>/// 删除观察者/// </summary>/// <param name="observer"></param>void RemoveObserver(IObserver observer);/// <summary>/// 通知观察者/// </summary>/// <param name="message"></param>void NoticeObserver(string message);
}
IObserver.cs
/// <summary>
/// 抽象观察者
/// </summary>
public interface IObserver
{/// <summary>/// 更新消息/// </summary>/// <param name="message"></param>void UpdateMessage(string message);
}
ConcreteSubject.cs
using System.Collections.Generic;/// <summary>
/// 具体被观察者
/// </summary>
public class ConcreteSubject : ISubject
{private List<IObserver> observers = new List<IObserver>();//存储观察者的容器public void AddObserver(IObserver observer){observers.Add(observer);}public void RemoveObserver(IObserver observer){observers.Remove(observer);}public void NoticeObserver(string message){for (int i = 0; i < observers.Count; i++){observers[i].UpdateMessage(message);}}
}
ConcreteObserver.cs
using UnityEngine;/// <summary>
/// 具体观察者
/// </summary>
public class ConcreteObserver : IObserver
{private string name;//观察者的名字public ConcreteObserver(string name){this.name = name;}public void UpdateMessage(string message){Debug.Log(name + "---接到消息: " + message);}
}
新建一个MyObserver.cs,内容如下:
using UnityEngine;public class MyObserver : MonoBehaviour
{private void Awake(){ConcreteSubject concreteSubject = new ConcreteSubject();//定义一个主题ConcreteObserver concreteObserver01 = new ConcreteObserver("李先生");//实例化一个观察者ConcreteObserver concreteObserver02 = new ConcreteObserver("王女士");//实例化一个观察者//李先生和王女士订阅该主题concreteSubject.AddObserver(concreteObserver01);concreteSubject.AddObserver(concreteObserver02);concreteSubject.NoticeObserver("俄罗斯和乌克兰打起来了");//通知所有观察者(订阅者)//王女士取消订阅该主题concreteSubject.RemoveObserver(concreteObserver02);concreteSubject.NoticeObserver("国际形势逐步紧张起来");//通知所有观察者(订阅者)}
}
最终输出如下:
相关文章:

游戏设计模式
单列模式 概念 单例模式是一种创建型设计模式,可以保证一个类只有一个实例,并提供一个访问该实例的全局节点。 优点 可以派生:在单例类的实例构造函数中可以设置以允许子类派生。受控访问:因为单例类封装他的唯一实例…...
CUBEMX与FreeRTOS在Arm Compiler 6下的配置方法
在嵌入式开发中,STM32是一种广泛使用的微控制器。为了提高开发效率,我们通常会利用ST公司提供的STM32CubeMX工具来配置硬件,并结合FreeRTOS这一实时操作系统来进行多任务处理。本文将深入探讨如何在这一框架下,使用Arm Compiler 6…...

Android Studio 提示Use app:drawableStartCompat instead of android:drawableStart
每次提交代码时,AS这个老妈子总爱唠叨一堆warning,这些Warning都在讲什么? 1.Use app:drawableStartCompat instead of android:drawableStart 在Android开发中,android:drawableStart和app:drawableStartCompat是两个用于设置…...

C# wpf 实现任意控件(包括窗口)更多调整大小功能
WPF拖动改变大小系列 第一节 Grid内控件拖动调整大小 第二节 Canvas内控件拖动调整大小 第三节 窗口拖动调整大小 第四节 附加属性实现拖动调整大小 第五章 拓展更多调整大小功能(本章) 文章目录 WPF拖动改变大小系列前言一、添加的功能1、任意控件Drag…...

Vue+OpenLayers7入门到实战:快速搭建Vue+OpenLayers7地图脚手架项目。从零开始构建Vue项目并整合OpenLayers7.5.2
返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7 前言 本章针对Vue初学者,对Vue不熟悉,甚至还不会Vue的入门学生读者。 本章会详细讲解从NodeJS环境到npm环境的各个步骤,再到使用vue-cli脚手架快速生成项目,以及添加OpenLayers7地图库依赖,编写简单的xyz高德地图显示…...
mysql-线上常用运维sql
1.表备份 INSERT INTO table1 SELECT * FROM table2; 2.用一个表中的字段更新另一张表中的字段 UPDATE table2 JOIN table1 ON table2.id table1.id SET table2.column2 table1.column1; 3.在MySQL中,查询一个表的列字段值是否包含另一个表的字段,…...

Linux之进程间通信(system V 共享内存)
目录 一、共享内存 1、基本原理 2、共享内存的创建 3、共享内存的释放 4、共享内存的关联 5、共享内存的去关联 6、查看IPC资源 二、完整通信代码 三、共享内存的特点 四、信号量 1、相关概念 2、信号量概念 进程间通信的本质就是让不同的进程看到同一个资源。而前…...

数据库 sql select *from account where name=‘张三‘ 执行过程
select *from account where name张三分析上面语句的执行过程 用到了索引 由于是根据 1.name字段进行查询,所以先根据name张三’到name字段的二级索引中进行匹配查 找。但是在二级索引中只能查找到 Arm 对应的主键值 10。 2.由于查询返回的数据是*,…...

力扣日记1.27-【回溯算法篇】131. 分割回文串
力扣日记:【回溯算法篇】131. 分割回文串 日期:2023.1.27 参考:代码随想录、力扣 131. 分割回文串 题目描述 难度:中等 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可…...

如何用web界面打开华为防火墙
目录 1.创建一个虚拟网卡 2.cloud操作 3.防火墙上操作 4. 登录 1.创建一个虚拟网卡 2.cloud操作 3.防火墙上操作 4. 登录...

力扣20、有效的括号(简单)
1 题目描述 图1 题目描述 2 题目解读 给定的字符串只包含括号,判断这个字符串中的括号是否按照正确顺序出现,即这个字符串是否有效。 3 解法一:栈 C的STL中的stack,在解题时非常好用。 3.1 解题思路 使用栈stk,并枚举…...

Android 系统启动过程
当按下电源时,引导芯片代码会从预定义的地方(固化在ROM) 开始执行,加载引导程序BootLoader到RAM,然后执行。 启动内核的第一个进程idle(pid0),idle进程是Linux系统第一个进程,是init进程和kthreadd进程的父进程。 idle的主要作用 初始化进程以及内存管…...

基于STM32的智能手环设计与实现
需要原理图工程,源码,PCB工程的朋友收藏,这篇文章关注我,私我吧!!! 基于STM32的智能手环设计与实现 摘要一、研究背景及意义二、实现功能三、系统方案设计系统方案设计框图3.1 单片机芯片选择3…...

[BJDCTF2020]The mystery of ip
hint 猜测ip和XFF有关 加一个XFF 下面这一步是看了wp出来的:存在ssti 这里尝试用jinja的注入方法,页面回显了是php的smarty框架 查了一下smarty的注入方法,发现可以直接执行php命令 在根目录找到flag...

RUST笔记:candle使用基础
candle介绍 candle是huggingface开源的Rust的极简 ML 框架。 candle-矩阵乘法示例 cargo new myapp cd myapp cargo add --git https://github.com/huggingface/candle.git candle-core cargo build # 测试,或执行 cargo ckeckmain.rs use candle_core::{Device…...

Python算法题集_接雨水
本文为Python算法题集之一的代码示例 题目42:接雨水 说明:给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1]…...
FIND_IN_SET的使用:mysql表数据多角色、多用户查询
MySQL 函数 FIND_IN_SET 是用于在逗号分隔的字符串中查找特定值的函数。它的语法如下: FIND_IN_SET(search_value, comma_separated_string)search_value 是要查找的值。 comma_separated_string 是逗号分隔的字符串,在这个字符串中查找指定的值。FIND_…...

JVM篇----第十一篇
系列文章目录 文章目录 系列文章目录前言一、在新生代-复制算法二、在老年代-标记整理算法三、分区收集算法四、GC 垃圾收集器前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你…...

鸿蒙HarmonyOS获取GPS精确位置信息
参考官方文档 #1.初始化时获取经纬度信息 aboutToAppear() {this.getLocation() } async getLocation () {try {const result await geoLocationManager.getCurrentLocation()AlertDialog.show({message: JSON.stringify(result)})}catch (error) {AlertDialog.show({message…...

java正则校验,手机号,邮箱,日期格式,时间格式,数字金额两位小数
java正则校验,手机号,邮箱,日期格式,时间格式,数字金额两位小数 3.58是否为金额:true 3.582是否为金额:false 1284789qq.com是否为email:true 1284789qq.com是否为email࿱…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...