unity 常用的设计模式

一、单例模式

在我们的整个游戏生命周期当中,有很多对象从始至终有且只有一个。这个唯一的实例只需要生成一次,并且直到游戏结束才需要销毁。
单例模式一般应用于管理器类,或者是一些需要持久化存在的对象。

优点:写起来很方便,调用方便。
缺点:容易形成依赖,忽略与其他设计模式的协作。

Unity的两种单例模式

  • 继承MonoBehaviour的单例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GameManager : MonoBehaviour
{
    
    
    public static GameManager _instance;void Awake()
    {
    
    
        _instance = this;
    }
}
  • 不继承MonoBehaviour的单例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class InstanceManager
{
    
    
    private static InstanceManager _instance;
    public static InstanceManager Instance
    {
    
    
        get
        {
    
    
            if (_instance == null)
            {
    
    
                _instance = new InstanceManager();
            }
            return _instance;
        }
    }}

二、工厂模式

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。
2、Hibernate 换数据库只需换方言和驱动就可以。

优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点: 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

以生产车来举例,有吉利,红旗,大众三个类型,这三种都是车,那我们先写一个车接口Car 也可以使用基类,表现效果一样,三类人都 有Productionr 的方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface Car
{
    
    
    void Production();
}

public class VW :Car
{
    
    
    public void Production()
    {
    
    
        Debug.Log("生产一辆大众");
    }
}

public class GeelyAutomobile : Car
{
    
    
    public void Production()
    {
    
    
        Debug.Log("生产一辆吉利");
    }
}

public class RedFlagCar : Car
{
    
    
    public void Production()
    {
    
    
        Debug.Log("生产一辆红旗");
    }
}

三种车的类已经创建好了,要开始进行工厂生产了,创建一个工厂类Clientele,传入约定好的字符串/Int/ 类型,即可以开始生产了,这里用一个静态的生产方法来进行生产,所以简单工厂模式又被称为静态生产模式。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Clientele
{
    
    

    public static Car Clienteles(string carname)
    {
    
    
        switch (carname)
        {
    
    
            case "VW":
                return new VW();

            case "GeelyAutomobile":
                return new GeelyAutomobile();

            case "RedFlagCar":
                return new RedFlagCar();

            default:
                break;
        }
        return null;
    }
}

现在我们要做个测试了,要去生产加工车了,只需要传入想生产的类型,即可返回你所需要的的实例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Texter : MonoBehaviour {
    
    

    void Start()
    {
    
    
        VW vW = (VW) Clientele.Clienteles("VW");
        vW.Production();

        GeelyAutomobile geelyAutomobile = (GeelyAutomobile)Clientele.Clienteles("GeelyAutomobile");
        geelyAutomobile.Production();

        RedFlagCar redFlagCar = (RedFlagCar)Clientele.Clienteles("RedFlagCar");
        redFlagCar.Production();
    }
}

将Test.cs 脚本扔到场景中,运行看看吧
在这里插入图片描述

观察者模式

对应的就是事件机制,通过添加监听者来获取状态变化。

主要解决:

观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性(本句来自百度百科)。
用我自己的理解解释一下上面那句,使用观察者模式可以避免类之间的直接调用,减少耦合,就是说类A需要监听类B,但是即使类B不在,也是可以运行的。

何时使用: 一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

应用实例:

1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。
2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。
3、遇到的例子有下层和上层的通讯,框架在设计上是保持单向依赖的,即上层依赖下层,视图层从业务层获取数据,业务层依赖基础类库。
但是下层也需要获得上层的状态变化,为了不违反单向依赖的原则就可以使用观察者模式监听上层来获取状态变化。

优点:

1、观察者和被观察者是抽象耦合的。
2、建立一套触发机制。

缺点:

1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

命令模式

命令模式就是将对象的状态和行为进行封装后按照一定的规则进行处理的模式。

主要解决: 可以把行为的请求者和行为的实现者分开,比如现在需要在游戏中开启录制,则需要记录输入的指令,如果 行为的请求者和实现者紧耦合(按下按键就执行)是不利于实现录制的。

优点:

1、降低了系统耦合度。
2、新的命令可以很容易添加到系统中去。
3、这个模式的优点第一个是减低耦合度,比如上面这个例子。其次因为请求者和实现着分开,我们可以对请求的指令做很多操作,比如增加新的指令,修改指令等。

实例: 我实际遇到的有个例子是模块之间的通讯,比如我的游戏有登录模块和网络模块,当登录模块收的登录信息时需要通过网络模块发送信息给服务器进行验证,如果直接调用网络模块的XXX函数,假设这个函数还没写甚至还没写网络模块,游戏就不能运行调试,这时候可以写一个模块管理器,如果需要调用另一个模块的函数,则通过发送一个消息给模块管理器来发送信息,如果模块不存在就缓存信息,等有的时候再发送过去。这属于静态解耦,就是编译上解耦,即使另一个模块还没有的时候也能运行。

以补充两个设计模式,可以看看,如果有问题或错误,欢迎大家提出,感谢!!!
后续会补充 今天就写到这里
谢谢各位大佬捧场

猜你喜欢

转载自blog.csdn.net/m0_47605113/article/details/111589335