Unity 实现代理模式

代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供了一种代理以控制对该对象的访问。代理模式的核心是通过一个代理对象来控制对目标对象的访问,可以在访问目标对象之前或之后添加额外的行为。

在Unity中,代理模式非常适合用来控制资源的访问(如懒加载资源、网络请求封装)或添加一些附加功能(如日志记录、访问权限检查等)。


1. 代理模式的基本概念

核心结构

代理模式包含以下主要角色:

  1. 抽象主题(Subject):定义目标对象和代理对象的公共接口,客户端通过这个接口与目标对象或代理对象交互。
  2. 真实主题(RealSubject):实现抽象主题接口,定义目标对象的实际行为。
  3. 代理(Proxy):实现抽象主题接口,持有对真实主题的引用,控制对真实主题的访问。

优点

  1. 控制对象访问:通过代理可以控制对目标对象的访问权限。
  2. 延迟加载:可以延迟加载资源,提高性能。
  3. 增强功能:在访问目标对象之前或之后添加额外的行为。

缺点

  1. 增加复杂性:引入代理对象会增加系统的复杂性。
  2. 性能开销:代理对象可能会增加调用的开销,尤其是远程代理。

2. Unity 实现代理模式

以下通过一个 虚拟资源加载系统 的示例,展示如何在Unity中实现代理模式。该系统包括:

  • 一个真实资源加载器(RealResourceLoader),负责加载资源。
  • 一个代理资源加载器(ProxyResourceLoader),负责控制资源的加载逻辑(如延迟加载、日志记录等)。

3. 实现步骤

(1) 定义抽象主题接口

创建一个接口,定义资源加载的公共行为。

// IResourceLoader.cs
public interface IResourceLoader
{
    void LoadResource(string resourceName); // 加载资源的方法
}

(2) 实现真实主题

创建一个真实资源加载器,负责实际的资源加载逻辑。

// RealResourceLoader.cs
using UnityEngine;

public class RealResourceLoader : IResourceLoader
{
    public void LoadResource(string resourceName)
    {
        Debug.Log($"Loading resource: {resourceName}");
        // 模拟资源加载逻辑
    }
}

(3) 实现代理

创建一个代理资源加载器,控制对真实资源加载器的访问。在这里可以添加日志记录或延迟加载逻辑。

// ProxyResourceLoader.cs
using UnityEngine;

public class ProxyResourceLoader : IResourceLoader
{
    private RealResourceLoader _realLoader;

    public void LoadResource(string resourceName)
    {
        if (_realLoader == null)
        {
            _realLoader = new RealResourceLoader(); // 延迟初始化真实加载器
        }

        Debug.Log("Proxy: Checking access before loading resource...");
        _realLoader.LoadResource(resourceName); // 调用真实加载器的加载方法
        Debug.Log("Proxy: Resource loading completed.");
    }
}

(4) 测试代理模式

创建一个测试脚本,模拟资源加载的过程。

// GameManager.cs
using UnityEngine;

public class GameManager : MonoBehaviour
{
    void Start()
    {
        // 使用代理加载资源
        IResourceLoader resourceLoader = new ProxyResourceLoader();

        Debug.Log("Requesting resource loading...");
        resourceLoader.LoadResource("PlayerModel"); // 加载玩家模型资源

        Debug.Log("Requesting another resource loading...");
        resourceLoader.LoadResource("EnemyModel"); // 加载敌人模型资源
    }
}

4. 运行结果

运行游戏后,控制台输出如下:

Requesting resource loading...
Proxy: Checking access before loading resource...
Loading resource: PlayerModel
Proxy: Resource loading completed.
Requesting another resource loading...
Proxy: Checking access before loading resource...
Loading resource: EnemyModel
Proxy: Resource loading completed.

5. 扩展性

(1) 添加访问控制

可以在代理中添加权限检查逻辑。例如,只有管理员角色可以加载某些资源:

// ProxyResourceLoader.cs
public class ProxyResourceLoader : IResourceLoader
{
    private RealResourceLoader _realLoader;

    public void LoadResource(string resourceName)
    {
        if (!HasAccess(resourceName))
        {
            Debug.LogWarning("Proxy: Access denied for resource: " + resourceName);
            return;
        }

        if (_realLoader == null)
        {
            _realLoader = new RealResourceLoader();
        }

        Debug.Log("Proxy: Checking access before loading resource...");
        _realLoader.LoadResource(resourceName);
        Debug.Log("Proxy: Resource loading completed.");
    }

    private bool HasAccess(string resourceName)
    {
        // 模拟权限检查
        return resourceName != "RestrictedResource";
    }
}

测试:

resourceLoader.LoadResource("RestrictedResource");
// 输出:
// Proxy: Access denied for resource: RestrictedResource

(2) 添加缓存逻辑

可以在代理中添加缓存逻辑,以减少重复加载的性能开销:

// ProxyResourceLoader.cs
using System.Collections.Generic;

public class ProxyResourceLoader : IResourceLoader
{
    private RealResourceLoader _realLoader;
    private HashSet<string> _loadedResources = new HashSet<string>();

    public void LoadResource(string resourceName)
    {
        if (_loadedResources.Contains(resourceName))
        {
            Debug.Log($"Proxy: Resource {resourceName} is already loaded. Using cached version.");
            return;
        }

        if (_realLoader == null)
        {
            _realLoader = new RealResourceLoader();
        }

        Debug.Log("Proxy: Checking access before loading resource...");
        _realLoader.LoadResource(resourceName);
        _loadedResources.Add(resourceName);
        Debug.Log("Proxy: Resource loading completed.");
    }
}

测试:

resourceLoader.LoadResource("PlayerModel");
// 输出:
// Proxy: Checking access before loading resource...
// Loading resource: PlayerModel
// Proxy: Resource loading completed.

resourceLoader.LoadResource("PlayerModel");
// 输出:
// Proxy: Resource PlayerModel is already loaded. Using cached version.

(3) 应用到其他场景
  • 网络请求代理:代理模式可以封装网络请求逻辑,添加日志或重试机制。
  • 权限代理:限制某些功能的访问(如菜单选项、管理面板)。
  • 虚拟代理:延迟初始化某些耗资源的对象(如大型纹理、模型)。

6. 优化与注意事项

(1) 代理的职责不要过多

代理的职责应该集中在控制访问,而不应替代真实主题的核心功能。

(2) 避免性能瓶颈

如果代理在访问过程中引入了大量的额外逻辑(例如频繁的权限检查或复杂的缓存机制),可能会导致性能下降。

(3) 真实主题的多态性

确保代理与真实主题实现相同的接口,以便客户端可以透明地使用代理或真实主题。


7. 总结

代理模式的优缺点
优点缺点
控制对目标对象的访问,提供额外功能。引入了额外的代理对象,增加了系统复杂性。
支持延迟加载、权限检查、日志记录等功能扩展。可能会引入性能开销(例如频繁的权限检查或缓存逻辑)。
真实主题可以集中于核心功能,代理负责辅助功能。需要确保代理与真实主题的接口一致,维护成本可能较高。

适用场景
  1. 需要控制对目标对象的访问(如权限检查、日志记录)。
  2. 需要延迟加载资源或对象(如虚拟代理)。
  3. 需要在访问目标对象前后添加额外的行为。

通过代理模式,Unity项目的功能扩展可以变得更加灵活,同时也可以提高系统的安全性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小宝哥Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值