游戏设计模式

单列模式

概念

单例模式是一种创建型设计模式,可以保证一个类只有一个实例,并提供一个访问该实例的全局节点。

优点

  • 可以派生:在单例类的实例构造函数中可以设置以允许子类派生。
  • 受控访问:因为单例类封装他的唯一实例,所以它可以严格的控制其他程序怎样以及何时访问它。
  • 可以获得一个指向该实例的全局访问节点。
  • 仅在首次请求单例对象时对其进行初始化。

缺点

  • 违反了单一职责原则。
  • 单例模式一般不要支持序列化,因为这也有可能导致多个对象实例。
  • 多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。

组成

1.单例(Singleton)类声明了一个名为get­Instance的静态方法来返回其所属类的一个相同实例。

2.单例的构造函数必须私有化,即对客户端(Client)隐藏。调用get­Instance方法必须是获取单例对象的唯一方式。

案例

方式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("国际形势逐步紧张起来");//通知所有观察者(订阅者)
    }
}

最终输出如下:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学习笔记-李沐动手学深度学习(五)(14-15,数值稳定性、模型初始化和激活函数、Kaggle房价预测)

总结 14-数值稳定性&#xff08;梯度爆炸、梯度消失&#xff09; 尤其是对于深度神经网络&#xff08;即神经网络层数很多&#xff09;&#xff0c;最终的梯度就是每层进行累乘 理论 t&#xff1a;为第t层 y&#xff1a;不是之前的预测值&#xff0c;而是包括了损失函数L …

统一聚合支付系统一个支付系统包含微信支付宝支付接口可对外提供多个网站使用同一个支付系统的初探与逻辑图

#聚合支付# #小李子9479# 开发背景 作为一个合格的站长或者运营&#xff0c;基本上都有好几个网站&#xff0c;而变现的方式其中之一就是付费。经常使用的付费包含微信支付和支付宝支付。微信的jsapi支付需要使用到openid&#xff0c;而获取openid需要设置授权域名&#xff…

C#用TimeSpan的Days、Hours、Minutes及Seconds属性确定程序的运行时间

目录 一、TimeSpan结构的Days、Hours、Minutes及Seconds属性 1.Days属性 2.Hours属性 3.Minutes属性 4.Seconds属性 二、确定程序运行时间的方法 1.实例源码 2.生成效果 在程序设计过程中&#xff0c;经常需要在主窗体中动态地显示程序的运行时间。 一、TimeSpan结构的…

【Linux】-同步互斥的另一种办法-信号量

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

身份证也可以cisa远程考试

CISA CISM CRISC CGEIT ​只有身份证 ​没有护照 ​没有港澳通行证 ​也可以线上考试

python学习20

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

object detection的一些pre trained模型(视频可以实现一下)

https://www.youtube.com/watch?v2yQqg_mXuPQ 你的支持是我创作的源泉

CC++内存管理【非常详细,对新手友好】

文章目录 一、程序内存划分1.基础知识2. 堆栈的区别3. 题目练手 二、C语言中动态内存管理方式三、C中动态内存管理方式1. new/delete操作内置类型2. new/delete操作自定义类型 四、operator new和operator delete函数1. 汇编查看编译器底层调用2. 透过源码分析两个全局函数 五、…

老旧小区火灾频发,LoRa无线系统筑牢安全防线

近日&#xff0c;全国各地多个老旧小区火灾事故频发&#xff0c;从安微合肥南二环一老旧小区居民楼起火、上海金山区一小区居民楼火灾&#xff0c;到1月24日江西新余市特大火灾......都造成了不同程度的人员伤亡和财产损失&#xff0c;令人扼腕痛惜&#xff0c;教训十分深刻。 …

浅谈 ts的类型校验 经验分享

经验1&#xff1a; 【input"testVal $event.target.value"】会有一个ts报错&#xff1a;【“$event.target”可能为 “null”。】我们可以使用【input"testVal (<HTMLInputElement>$event.target).value"】解决ts报错<input type"text&quo…

C#-前后端分离连接mysql数据库封装接口

C#是世界上最好的语言 新建项目 如下图所示选择框红的项目 然后新建 文件夹 Common 并新建类文件 名字任意 文件内容如下 因为要连接的是mysql数据库 所以需要安装 MySql.Data.MySqlClient 依赖; using MySql.Data.MySqlClient; using System.Data;namespace WebApplication1.…

【Image captioning】论文阅读八—ClipCap: CLIP Prefix for Image Captioning_2021

中文标题&#xff1a;ClipCap: CLIP前缀用于图像描述&#xff08;ClipCap: CLIP Prefix for Image Captioning&#xff09; 文章目录 1. 介绍2. 相关工作3. 方法3.1 综述3.2 语言模型微调3.3 映射网络架构3.4 推理 4. 结果5. 结论 摘要&#xff1a;图像描述是视觉语言理解中的…

黑群晖屏蔽更新

黑群晖屏蔽更新 修改Host删除控制面板的红点和更新提示 修改Host ssh连接群晖后执行以下命令 sudo vim /etc/hosts按i键进入编辑模式 光标移动定位到最后一行后追加以下两行 127.0.0.1 update.synology.com 127.0.0.1 update7.synology.com按esc键&#xff0c;然后输入:wq并…

Nginx进阶篇【四】

Nginx进阶篇【四】 六、Nginx负载均衡6.1.负载均衡概述6.2.负载均衡的原理及处理流程6.3.负载均衡的作用6.4.负载均衡常用的处理方式6.4.1.方式一:用户手动选择6.4.2.方式二:DNS轮询方式6.4.2.1.DNS6.4.2.2.为某一个域名添加的IP地址&#xff0c;用2台服务器来做负载均衡6.4.2.…

ROS2学习笔记(0)开坑声明

0.前提 在做racecar的过程中发现已经有不少的开发者和公司开始从ros1转向ros2的怀抱了&#xff0c;刚好寒假在家&#xff0c;我就顺带试试看能不能学点ros2&#xff0c;刚好我有两辆车和主板可以双线开工&#xff08;是的&#xff0c;全是老师们赞助的&#xff0c;真的我哭死&…

Java面试题之序列化和反序列化

Java面试题之序列化和反序列化 文章目录 Java面试题之序列化和反序列化序列化和反序列化什么是序列化?什么是反序列化?如果有些字段不想进行序列化怎么办&#xff1f;常见序列化协议有哪些&#xff1f;为什么不推荐使用 JDK 自带的序列化&#xff1f; 文章来自Java Guide 用于…

Python初学者学习记录——python基础综合案例:数据可视化——地图可视化

一、基础地图使用 1、基础地图演示 2、基础地图演示——视觉映射器 from pyecharts.charts import Map from pyecharts.options import VisualMapOpts# 准备地图对象 map Map() # 准备数据 data [("北京市", 99),("上海市", 199),("湖南省", 2…

stable-diffusion-webui 汉化(中文界面)

大家好&#xff0c;我是水滴~~ 本文主要介绍 Stable Diffusion WebUI 是如何汉化的&#xff0c;文章详细的介绍汉化过程&#xff0c;并加上配图能够清晰的展示该过程。 Stable Diffusion WebUI 官方并没有出中文界面&#xff0c;需要通过安装插件来汉化&#xff0c;下面是详细…

MySQL-进阶-SQL优化

一、insert优化 插入大量数据 二、主键优化 1、数据组织方式 2、页分裂 3、页合并 4、逐渐设计原则 三、order by优化 四、group by优化 五、limit优化 六、count优化 七、update优化

3 JS类型 值和变量

计算机对value进行操作。 value有不同的类型。每种语言都有其自身的类型集合。编程语言的类型集是该编程语言的基本特性。 value需要保存一个变量中。 变量的工作机制是变成语言的另一个基本特性。 3.1概述和定义 JS类型分为&#xff1a; 原始类型和对象类型。 原始类型&am…