设计模式学习记录

设计模式

单例模式

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : Singleton<T>

{

    private static T instance;

    public static T Instance

    {

        get { return instance; }

    }

    protected virtual void Awake()

    {

        if (instance != null)

        {

            Destroy(gameObject);

        }

        else

            instance = (T)this;

    }

    public static bool IsInitialized

    {

        get { return instance != null; }

    }

    protected virtual void OnDestroy()

    {

        if (instance == this)

        {

            instance = null;

        }

    }

}

对象池模式

using System.Collections.Generic;

using UnityEngine;

public class ObjectPool<T> where T : Component

{

    private Stack<T> _pool = new Stack<T>();

    private readonly Transform _parent; // 用于存放对象池中的对象

    private readonly System.Func<T> _createFunc; // 创建对象的方法

    public ObjectPool(int initialSize, System.Func<T> createFunc, Transform parent)

    {

        _createFunc = createFunc;

        _parent = parent;

        for (int i = 0; i < initialSize; i++)

        {

            T obj = CreateObject();

            ReturnToPool(obj);

        }

    }

    private T CreateObject()

    {

        T obj = _createFunc();

        if (_parent != null)

        {

            obj.transform.SetParent(_parent, false);

        }

        return obj;

    }

    public T GetFromPool()

    {

        if (_pool.Count == 0)

        {

            Debug.LogWarning("Object pool is empty, creating a new object.");

            return CreateObject();

        }

        T obj = _pool.Pop();

        obj.gameObject.SetActive(true); // 激活对象

        return obj;

    }

    public void ReturnToPool(T obj)

    {

        obj.gameObject.SetActive(false); // 禁用对象

        _pool.Push(obj);

    }

}

// 使用示例

public class ExampleUsage : MonoBehaviour

{

    public GameObject prefab; // 要池化的预制件

    private ObjectPool<GameObject> _objectPool;

    private void Start()

    {

        // 初始化对象池,传入初始大小、创建方法和父物体

        _objectPool = new ObjectPool<GameObject>(10, () => Instantiate(prefab), transform);

    }

    private void Update()

    {

        if (Input.GetKeyDown(KeyCode.Space))

        {

            // 从池中获取对象

            GameObject obj = _objectPool.GetFromPool();

            // 设置对象位置

            obj.transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 10));

        }

    }

    // 返回对象到池中(通常由对象自身或其它逻辑触发)

    public void ReturnObject(GameObject obj)

    {

        _objectPool.ReturnToPool(obj);

    }

}

工厂模式

工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。通过工厂模式,一个类(称为“工厂”)负责决定应该实例化哪一个类,这使得代码更加灵活和易于维护。在Unity中,工厂模式可以用来管理游戏对象的创建,例如敌人、道具、子弹等。

1. 定义产品接口或基类

首先,我们需要定义一个所有具体产品都应该实现的接口或继承的基类。在这个例子中,我们将创建一个IEnemy接口,所有的敌人都将实现这个接口。

public interface IEnemy

{

    void Initialize();

    void Move();

    void Attack();

    void TakeDamage(int damage);

    void Die();

}

2. 创建具体的产品类

接下来,我们创建几个具体的敌人类型,它们都实现了IEnemy接口。

public class Orc : MonoBehaviour, IEnemy

{

    public void Initialize()

    {

        // 初始化逻辑

        Debug.Log("Orc Initialized");

    }

    public void Move()

    {

        // 移动逻辑

        Debug.Log("Orc Moving");

    }

    public void Attack()

    {

        // 攻击逻辑

        Debug.Log("Orc Attacking");

    }

    public void TakeDamage(int damage)

    {

        // 受损逻辑

        Debug.Log($"Orc takes {damage} damage");

    }

    public void Die()

    {

        // 死亡逻辑

        Debug.Log("Orc Died");

        Destroy(gameObject);

    }

}

// 可以添加更多类型的敌人...

3. 创建工厂类

现在,我们创建一个工厂类来负责创建这些敌人。这个工厂可以根据传入的参数决定创建哪种类型的敌人。

public class EnemyFactory : MonoBehaviour

{

    [System.Serializable]

    public class EnemyPrefab

    {

        public string enemyType;

        public GameObject prefab;

    }

    [SerializeField] private EnemyPrefab[] enemyPrefabs;

    private Dictionary<string, GameObject> _enemyDictionary = new Dictionary<string, GameObject>();

    private void Awake()

    {

        foreach (var enemyPrefab in enemyPrefabs)

        {

            _enemyDictionary[enemyPrefab.enemyType] = enemyPrefab.prefab;

        }

    }

    public IEnemy CreateEnemy(string type, Vector3 position, Quaternion rotation)

    {

        if (_enemyDictionary.TryGetValue(type, out GameObject prefab))

        {

            GameObject obj = Instantiate(prefab, position, rotation);

            return obj.GetComponent<IEnemy>();

        }

        else

        {

            Debug.LogError($"Enemy type '{type}' not found.");

            return null;

        }

    }

}

4. 使用工厂

最后,我们在需要的地方使用工厂来创建敌人。例如在Spawner脚本中:

public class Spawner : MonoBehaviour

{

    public EnemyFactory enemyFactory;

    public string enemyType; // 在Inspector中设置要生成的敌人类型

    public float spawnInterval = 2f;

    private void Start()

    {

        InvokeRepeating(nameof(SpawnEnemy), 0f, spawnInterval);

    }

    private void SpawnEnemy()

    {

        IEnemy enemy = enemyFactory.CreateEnemy(enemyType, transform.position, Quaternion.identity);

        if (enemy != null)

        {

            enemy.Initialize();

        }

    }

}

观察者模式

在Unity中,观察者模式可以用于实现事件驱动的架构,例如游戏中的敌人需要响应玩家的生命值变化,或者UI元素需要响应游戏角色的状态变化等。

1. 定义主题(Subject)接口

首先,我们定义一个ISubject接口,该接口包含添加、移除和通知观察者的操作。

using System;

using System.Collections.Generic;

public interface ISubject

{

    void RegisterObserver(IObserver observer);

    void RemoveObserver(IObserver observer);

    void NotifyObservers();

}

2. 创建具体的主题类

接下来,我们创建一个具体的主题类,例如Player,它可以注册和移除观察者,并在特定事件发生时通知它们。

public class Player : MonoBehaviour, ISubject

{

    private List<IObserver> _observers = new List<IObserver>();

    public event Action OnHealthChanged; // 当玩家生命值变化时触发的事件

    public int Health { get; private set; } = 100;

    public void TakeDamage(int damage)

    {

        Health -= damage;

        Debug.Log($"Player took {damage} damage, health is now {Health}");

        if (OnHealthChanged != null) OnHealthChanged(); // 触发事件

        NotifyObservers();

    }

    public void RegisterObserver(IObserver observer)

    {

        if (!_observers.Contains(observer))

        {

            _observers.Add(observer);

        }

    }

    public void RemoveObserver(IObserver observer)

    {

        _observers.Remove(observer);

    }

    public void NotifyObservers()

    {

        foreach (var observer in _observers)

        {

            observer.Update(this); // 通知每个观察者

        }

    }

}

3. 定义观察者(Observer)接口

然后,我们定义一个IObserver接口,该接口包含一个Update方法,这是所有观察者必须实现的方法。

public interface IObserver

{

    void Update(ISubject subject);

}

4. 创建具体的观察者类

现在,我们创建一些具体的观察者类,这些类实现了IObserver接口,并定义了如何响应主题的通知。

public class Enemy : MonoBehaviour, IObserver

{

    private Player _player;

    public void SetPlayer(Player player)

    {

        _player = player;

        _player.RegisterObserver(this); // 注册自己为观察者

    }

    public void Update(ISubject subject)

    {

        if (subject is Player player)

        {

            Debug.Log($"{name} received notification from Player: Health is {player.Health}");

            // 可以在这里添加敌人的反应逻辑,比如改变状态或攻击

        }

    }

    private void OnDestroy()

    {

        if (_player != null)

        {

            _player.RemoveObserver(this); // 移除自己作为观察者

        }

    }

}

public class UIManager : MonoBehaviour, IObserver

{

    private Player _player;

    public void SetPlayer(Player player)

    {

        _player = player;

        _player.RegisterObserver(this); // 注册自己为观察者

    }

    public void Update(ISubject subject)

    {

        if (subject is Player player)

        {

            Debug.Log("UIManager updating UI elements based on player's health");

            // 更新UI元素,如健康条

        }

    }

    private void OnDestroy()

    {

        if (_player != null)

        {

            _player.RemoveObserver(this); // 移除自己作为观察者

        }

    }

}5. 使用观察者模式

最后,在场景中创建Player、Enemy和UIManager实例,并将Enemy和UIManager设置为Player的观察者。

public class GameInitializer : MonoBehaviour

{

    public Player player;

    public Enemy enemy;

    public UIManager uiManager;

    private void Start()

    {

        // 将敌人和UI管理器注册为玩家的观察者

        enemy.SetPlayer(player);

        uiManager.SetPlayer(player);

        // 模拟玩家受到伤害

        player.TakeDamage(20);

    }

}

代理模式

代理模式可以在不改变原对象接口的情况下,添加额外的功能,如延迟加载、权限检查、日志记录等。在Unity中,代理模式可以用于网络通信、资源管理、性能优化等多种场景。

1. 定义主题接口

首先,我们定义一个接口,所有的真实主题和代理都将实现这个接口。这确保了客户端代码可以透明地与真实主题或代理交互。

public interface IGameService

{

    void LoadLevel(string levelName);

    void SaveProgress();

    void ExitGame();

}

2. 创建真实主题类

接下来,我们创建一个具体的GameService类,它实现了IGameService接口,并提供了实际的游戏服务功能。

public class GameService : IGameService

{

    public void LoadLevel(string levelName)

    {

        Debug.Log($"Loading level: {levelName}");

        // 实际的加载逻辑

    }

    public void SaveProgress()

    {

        Debug.Log("Saving game progress...");

        // 实际的保存逻辑

    }

    public void ExitGame()

    {

        Debug.Log("Exiting game...");

        // 实际的退出逻辑

    }

}

3. 创建代理类

现在,我们创建一个代理类GameServiceProxy,它也实现了IGameService接口。代理类可以在调用真实主题的方法之前或之后执行额外的操作,例如权限检查、日志记录等。

public class GameServiceProxy : IGameService

{

    private GameService _realService;

    public GameServiceProxy(GameService realService)

    {

        _realService = realService;

    }

    public void LoadLevel(string levelName)

    {

        // 在调用真实方法之前执行额外操作

        if (CheckPermissions())

        {

            LogAction("LoadLevel");

            _realService.LoadLevel(levelName);

        }

        else

        {

            Debug.LogWarning("Permission denied to load level.");

        }

    }

    public void SaveProgress()

    {

        // 在调用真实方法之前执行额外操作

        if (CheckPermissions())

        {

            LogAction("SaveProgress");

            _realService.SaveProgress();

        }

        else

        {

            Debug.LogWarning("Permission denied to save progress.");

        }

    }

    public void ExitGame()

    {

        // 在调用真实方法之前执行额外操作

        if (CheckPermissions())

        {

            LogAction("ExitGame");

            _realService.ExitGame();

        }

        else

        {

            Debug.LogWarning("Permission denied to exit game.");

        }

    }

    private bool CheckPermissions()

    {

        // 模拟权限检查逻辑

        return UnityEngine.Random.value > 0.5f; // 随机返回true或false

    }

    private void LogAction(string action)

    {

        // 记录日志

        Debug.Log($"[Log] Action: {action} called at {DateTime.Now}");

    }

}

4. 使用代理模式

最后,在需要的地方使用代理来代替直接调用真实主题。这样可以确保所有的调用都经过代理,从而执行额外的操作。

public class GameManager : MonoBehaviour

{

    private IGameService _gameService;

    private void Start()

    {

        // 创建真实的服务实例

        GameService realService = new GameService();

        // 创建代理实例,传入真实的服务

        _gameService = new GameServiceProxy(realService);

        // 使用代理来调用游戏服务的方法

        _gameService.LoadLevel("Level1");

        _gameService.SaveProgress();

        _gameService.ExitGame();

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值