游戏设计模式

单列模式

概念

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

优点

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

缺点

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

组成

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

最终输出如下:

最近更新

  1. TCP协议是安全的吗?

    2024-01-29 08:36:01       17 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-29 08:36:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-29 08:36:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-29 08:36:01       18 阅读

热门阅读

  1. VUE computed和watch例子

    2024-01-29 08:36:01       30 阅读
  2. [EFI]戴尔T5810电脑 Hackintosh 黑苹果efi引导文件

    2024-01-29 08:36:01       35 阅读
  3. 非root运行docker容器

    2024-01-29 08:36:01       40 阅读
  4. go标准库Context上下文

    2024-01-29 08:36:01       30 阅读
  5. web架构师编辑器内容-添加自动保存的功能

    2024-01-29 08:36:01       37 阅读
  6. 获取本机请求时真实ip

    2024-01-29 08:36:01       27 阅读
  7. Qt 分段Bezier曲线插值(2D)

    2024-01-29 08:36:01       45 阅读