Unity---游戏设计模式(11)之享元模式




概述参考请看 参考博客

享元模式:运用共享技术有效地支持大量细粒度的对象。

1、享元模式原型

享元模式原型UML图

享元模式原型代码

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

public class Client : MonoBehaviour
{
    private void Start () {
        FlyWeightFactory FlyWeightFactory = new FlyWeightFactory();

        FlyWeight FlyWeight1 = FlyWeightFactory.GetFlyWeight("MyFlyWeight");
        FlyWeight1.Operate();

        FlyWeight FlyWeight2 = FlyWeightFactory.GetFlyWeight("MyFlyWeight");
        FlyWeight2.Operate();

        FlyWeight FlyWeight3 = FlyWeightFactory.GetFlyWeight("YourFlyWeight");
        FlyWeight3.Operate();

        FlyWeight FlyWeight4 = FlyWeightFactory.GetFlyWeight("YourFlyWeight");
        FlyWeight4.Operate();

        FlyWeightFactory.ShowAllFlyWeights();
    }
}
/// <summary>
/// 享元抽象类
/// </summary>
public abstract class FlyWeight
{
    //享元模式的内部状态可以共享,但不会随环境的变化而变化。
    //外部状态不可以共享,但会随环境的变化而变化。这里说的是外部状态具有固化特性,即固有化的性质,不应该随【内部状态】的改变而改变,否则会导致系统的逻辑混乱
    
    //内部状态
    public string mInside;
    //外部状态
    protected string mOutside;
    public string Outside { get { return mOutside; } set { mOutside = Outside; } }

    public FlyWeight(string outside)
    {
        mOutside = outside;
    }

    public abstract void Operate();
}
/// <summary>
/// 具体的享元类
/// </summary>
public class ConcreteFlyWeight : FlyWeight
{
    public ConcreteFlyWeight(string outside)
        :base(outside)
    {}

    public override void Operate()
    {
        Debug.Log("外部状态:" + mOutside);
    }
}

/// <summary>
/// 享元工厂
/// </summary>
public class FlyWeightFactory
{
    private Dictionary<string, FlyWeight> mFlyWeightDict;

    public FlyWeightFactory()
    {
        mFlyWeightDict = new Dictionary<string, FlyWeight>();
    }

    /// <summary>
    /// 获取FlyWeight
    /// </summary>
    public FlyWeight GetFlyWeight(string name)
    {
        if (mFlyWeightDict.ContainsKey(name))
        {
            Debug.Log(name + ":已经存在字典中,直接返回");
            return mFlyWeightDict[name];
        }
        FlyWeight FlyWeight = new ConcreteFlyWeight(name);
        mFlyWeightDict.Add(name, FlyWeight);
        Debug.Log(name + ":不存在字典中,加入字典再返回");
        return FlyWeight;
    }

    public void ShowAllFlyWeights()
    {
        foreach (FlyWeight item in mFlyWeightDict.Values)
        {
            Debug.Log("FlyWeight:" + item.Outside);
        }
    }
}


2、享元模式实例

假设有青铜、白银、黄金三种敌人。
创建每种敌人时,每种敌人的基本属性是相同的。比如名字、血量之类的。
这些相同的基本属性如果我们每次创建角色时都重新构造,无疑麻烦而且占性能。

当我们使用(10)建造者模式来建造复杂的角色时,就可以在添加基本属性一步时,并使用享元模式直接获取到角色基本属性。
这里不再重复给出建造模式代码了,只给出了享元模式的部分代码

实例代码

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

public class Client : MonoBehaviour
{
    private void Start()
    {
        //假设有青铜、白银、黄金三种敌人。
        //创建每种敌人时,每种敌人的基本属性是相同的。比如名字、血量之类的。
        //这些相同的基本属性如果我们每次创建角色时都重新构造,无疑麻烦而且占性能。

        //当我们使用(10)的建造者模式来建造复杂的角色时,就可以在建造基本属性一步时,使用享元模式直接获取到角色属性。
        //这里不再重复给出建造模式代码了,只给出了享元模式的部分代码

        EnemyFactory factory = new EnemyFactory();

        EnemyBaseAttribute bronzeBaseAttribute = factory.GetEnemyBaseAttribute(EnemyType.Bronze);
        Debug.Log(bronzeBaseAttribute.Name + "血量:" + bronzeBaseAttribute.HP);

        EnemyBaseAttribute silverBaseAttribute = factory.GetEnemyBaseAttribute(EnemyType.Silver);
        Debug.Log(silverBaseAttribute.Name + "血量:" + silverBaseAttribute.HP);

        EnemyBaseAttribute goldBaseAttribute = factory.GetEnemyBaseAttribute(EnemyType.Gold);
        Debug.Log(goldBaseAttribute.Name + "血量:" + goldBaseAttribute.HP);
    }
}

public enum EnemyType
{
    Bronze,     //青铜
    Silver,     //白银
    Gold        //黄金
}

/// <summary>
/// 敌人相同的基本属性
/// </summary>
public class EnemyBaseAttribute
{
    #region 基本属性
    private string mName;
    private int mHP;
    private float mMoveSpeed;
    private string mPrefabName; 
    #endregion

    #region Get方法
    public string Name { get { return mName; } }
    public int HP { get { return mHP; } }
    public float MoveSpeed { get { return mMoveSpeed; } }
    public string PrefabName { get { return mPrefabName; } }
    #endregion

    public EnemyBaseAttribute(string name,int hp,float moveSpeed,string prefabName)
    {
        mName = name;
        mHP = hp;
        mMoveSpeed = moveSpeed;
        mPrefabName = prefabName;
    }
}

/// <summary>
/// 角色基本属性的工厂(更像享元模式和工厂模式一起用)
/// </summary>
public class EnemyFactory
{
    //存储每个敌人类型对应的基本属性
    private Dictionary<EnemyType, EnemyBaseAttribute> mEnemyBaseAttributeDict;

    public EnemyFactory()
    {
        mEnemyBaseAttributeDict = new Dictionary<EnemyType, EnemyBaseAttribute>();
        InitEnemyBaseAttributeDict();
    }

    /// <summary>
    /// 初始化三种敌人基本属性
    /// </summary>
    private void InitEnemyBaseAttributeDict()
    {
        mEnemyBaseAttributeDict.Add(EnemyType.Bronze, new EnemyBaseAttribute("青铜", 10, 1, "BronzeModel"));
        mEnemyBaseAttributeDict.Add(EnemyType.Silver, new EnemyBaseAttribute("白银", 30, 3, "SilverModel"));
        mEnemyBaseAttributeDict.Add(EnemyType.Gold, new EnemyBaseAttribute("黄金", 20, 2, "GoldModel"));
    }

    /// <summary>
    /// 获取敌人基本属性
    /// </summary>
    public EnemyBaseAttribute GetEnemyBaseAttribute(EnemyType type)
    {
        if (mEnemyBaseAttributeDict.ContainsKey(type))
        {
            return mEnemyBaseAttributeDict[type];
        }
        Debug.LogError("无法根据类型" + type + "得到角色基础属性");
        return null;
    }
}

3、享元模式优缺点

优点

  1. 减少了对象的创建,降低了程序内存的占用,提高效率。

缺点

  1. 提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态的改变而改变。
原文地址:https://www.cnblogs.com/Fflyqaq/p/11707957.html