(十一)享元模式:
当相同的角色(如多个新手士兵)共享多个不变的属性时,使不变的属性只存在一份(会变化的属性如 当前生命值、等级…),每次要使用的时候,就去储存相同属性的BaseAttr工厂中取得该属性,可减少所占用的内存。
——重构代码——
完成战士/敌人角色的构造(使用享元) :
将ICharacterAttr 中的基础属性删除,创建CharacterBaseAttr用于管理角色的相同基础属性:
/// <summary>
///管理游戏角色共有的属性
/// </summary>
public class CharacterBaseAttr
{
protected string mName;
protected int mMaxHp;
protected float mMoveSpeed;
protected string mIconSprite; // 资源加载
protected string mPrefabName;// 通过Prefab名字实例化Prefab
protected float mCritRate;//0-1暴击率
public CharacterBaseAttr(string Name, int MaxHp, float MoveSpeed, string IconSprite, string PrefabName, float CritRate)
{
this.mName = Name;
this.mMaxHp = MaxHp;
this.mMoveSpeed = MoveSpeed;
this.mIconSprite = IconSprite;
this.mPrefabName = PrefabName;
this.mCritRate = CritRate;
}
public string Name { get { return mName; } }
public int MaxHp { get { return mMaxHp; } }
public float MoveSpeed { get { return mMoveSpeed; } }
public string IconSprite { get { return mIconSprite; } }
public string PrefabName { get { return mPrefabName; } }
public float CritRate { get { return mCritRate; } }
}
创建工厂接口类IAttrFactory,写入用于得到角色基础的方法:
public interface IAttrFactory
{
CharacterBaseAttr GetCharacterBaseAttr(System.Type t);
}
创建工厂类AttrFactory(享元模式核心),用字典将 通过战士/敌人的类型来存储战士/敌人的基础属性,每次实例化战士/敌人只需要调用 得到角色基础属性的方法 ,不需要每次都在内存中存一份相同的基础属性。构造方法中将所有需要共享的对象初始化
/// <summary>
/// 享元模式核心
/// </summary>
public class AttrFactory : IAttrFactory
{
//通过角色类型来存储角色共有的属性
private Dictionary<Type, CharacterBaseAttr> mCharacterBaseAttrDict;
/// <summary>
/// 构造方法中将所有需要共享的对象初始化
/// </summary>
public AttrFactory()
{
InitCharacterBaseAttr();
}
private void InitCharacterBaseAttr()
{
//初始化字典
mCharacterBaseAttrDict = new Dictionary<Type, CharacterBaseAttr>();
mCharacterBaseAttrDict.Add(typeof(SoldierRookie), new CharacterBaseAttr("新手士兵", 80, 2.5f, "RookieIcon", "Soldier3", 0));
mCharacterBaseAttrDict.Add(typeof(SoldierSergeant), new CharacterBaseAttr("中士士兵", 90, 3, "SergeantIcon", "Soldier2", 0));
mCharacterBaseAttrDict.Add(typeof(SoldierCaptain), new CharacterBaseAttr("上尉士兵", 100, 3, "CaptainIcon", "Soldier1", 0));
mCharacterBaseAttrDict.Add(typeof(EnemyElf), new CharacterBaseAttr("小精灵", 100, 3, "ElfIcon", "Enemy1", 0.2f));
mCharacterBaseAttrDict.Add(typeof(EnemyOgre), new CharacterBaseAttr("怪物", 120, 2, "OgreIcon", "Enemy2", 0.3f));
mCharacterBaseAttrDict.Add(typeof(EnemyTroll), new CharacterBaseAttr("巨魔", 200, 1, "TrollIcon", "Enemy3", 0.2f));
}
/// <summary>
/// 得到角色基础属性
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public CharacterBaseAttr GetCharacterBaseAttr(Type t)
{
if (mCharacterBaseAttrDict.ContainsKey(t) == false)
{
Debug.LogWarning("无法根据类型["+t+"]得到角色的基础属性"); return null;
}
return mCharacterBaseAttrDict[t];
}
}
在FactoryManager中加入IAttrFactory 静态属性,可用于外界调用:
public static class FactoryManager
{
private static IAssetFactory mAssetFactory;
private static IWeaponFactory mWeaponFactory;
private static ICharacterFactory mSoldierFactory;
private static ICharacterFactory mEnemyFactory;
private static IAttrFactory mAttrFactory;
public static IAttrFactory attrFactory
{
get
{
if (mAttrFactory== null)
{
mAttrFactory= new ResourcesAssetFactory();
}
return mAttrFactory;
}
}
省略………
在ICharacterAttr中声明可被子类取得的属性 CharacterBaseAttr , 修改其构造方法,将基础属性 改为 CharacterBaseAttr类,并修改其子类的构造方法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ICharacterAttr
{
protected CharacterBaseAttr mCharacterBaseAttr;
protected int mLv;
protected int mCurrentHP;
protected int mDmgDescValue; //减少的伤害
public int CurrentHP { get { return mCurrentHP; } }
private IAttrStrategy mStrategy;
//角色实例化时就决定属性,后续不改变
public ICharacterAttr(IAttrStrategy strategy, int lv, CharacterBaseAttr characterBaseAttr)
{
mCharacterBaseAttr = characterBaseAttr;
mLv = lv;
mStrategy = strategy;
mDmgDescValue = mStrategy.GetCritDmg(mCharacterBaseAttr.CritRate);
mCurrentHP = mCharacterBaseAttr.MaxHp + mStrategy.GetExtraHPValue(mLv);
}
public int CritValue { get { return mStrategy.GetCritDmg(mCharacterBaseAttr.CritRate); } }
/// <summary>
/// 被攻击后的处理
/// </summary>
/// <param name="damage">受到的伤害</param>
public void TakeDamege(int damage)
{
damage -= mDmgDescValue;
if (damage <= 5) damage = 5;
mCurrentHP -= damage;
}
}
修改SoldierBuilder 和 EnemyrBuilder的 AddCharacterAttr() 给角色添加属性的方法:
通过FactoryManager调用attrFactory 属性工厂的 GetCharacterBaseAttr()方法,得到角色基础属性:
public class SoldierBuilder : ICharacterBuilder
{
public SoldierBuilder(ICharacter character, Type t, WeaponType weaponType, Vector3 spawnPos, int lv) : base(character, t, weaponType, spawnPos, lv){
}
public override void AddCharacterAttr()
{
CharacterBaseAttr characterBaseAttr = FactoryManager.attrFactory.GetCharacterBaseAttr(mT);
mPrefabName = characterBaseAttr.PrefabName;
ICharacterAttr attr = new SoldierAttr(new SoldierAttrStrategy(), mLV, characterBaseAttr);
mCharacter.CharacterAttri = attr;
}
public class EnemyrBuilder : ICharacterBuilder
{
public EnemyrBuilder(ICharacter character, Type t, WeaponType weaponType, Vector3 spawnPos, int lv) : base(character, t, weaponType, spawnPos, lv){ }
public override void AddCharacterAttr()
{
CharacterBaseAttr characterBaseAttr = FactoryManager.attrFactory.GetCharacterBaseAttr(mT);
mPrefabName = characterBaseAttr.PrefabName;
ICharacterAttr attr = new EnemyAttr(new EnemyAttrStrategy(), mLV, characterBaseAttr);
mCharacter.CharacterAttri = attr;
}
省略……
将武器属性修改为享元模式 :
将IWeaponAttr 中的基础属性删除,创建CharacterBaseAttr用于管理角色的基础属性:
public class WeaponBaseAttr
{
protected string mName;
protected int mAtk;//最大攻击力
protected float mAtkRange;//最大攻击范围
protected string mAssetsName;//资源名称
public WeaponBaseAttr(string Name,int Atk,float AtkRange,string AssetsName)
{
mName = Name;
mAtk = Atk;
mAtkRange = AtkRange;
mAssetsName = AssetsName;
}
public string Name { get { return mName; } }
public int Atk { get { return Atk; } }
public float AtkRange { get { return mAtkRange; } }
public string AssetsName { get { return mAssetsName; } }
}
在IWeaponAttr 中声明可被子类取得的属性 WeaponBaseAttr , 修改其构造方法,将基础属性 改为 WeaponBaseAttr 类,并
修改其子类的构造方法
public abstract class IWeapon
{
//protected int mAtkPlusValue;//暴击
protected WeaponBaseAttr mWeaponBaseAttr;
protected GameObject mGameObject;//武器模型
protected ICharacter mOwner;//武器持有者
protected ParticleSystem mParticle;//武器特效
protected LineRenderer mLineRender;//武器射线
protected Light mLight;
protected AudioSource mAudioSource; //音效
protected float mEffectDisplayTime;//特效显示时间
public float AtkRange { get { return mWeaponBaseAttr.AtkRange; } }
public float Atk { get { return mWeaponBaseAttr.Atk; } } // 武器攻击力
public ICharacter Owner { set { mOwner = value; } }
public GameObject gameObject { get { return mGameObject; } }
public IWeapon(WeaponBaseAttr weaponBaseAttr, GameObject gameObject)
{
mWeaponBaseAttr = weaponBaseAttr;
mGameObject = gameObject;
//得到武器特效射线灯光音效的组件,在武器的子物体Effect中
Transform effect = mGameObject.transform.Find("Effect");
mParticle = effect.GetComponent<ParticleSystem>();
mLineRender = effect.GetComponent<LineRenderer>();
mLight = effect.GetComponent<Light>();
mAudioSource = effect.GetComponent<AudioSource>();
}
在IAttrFactory中加入得到武器基础属性的方法:
public interface IAttrFactory
{
CharacterBaseAttr GetCharacterBaseAttr(System.Type t);
WeaponBaseAttr GetWeaponBaseAttr(WeaponType weaponType);
}
在AttrFactory中用字典将 通过武器的类型来存储武器的基础属性,每次实例化武器只需要调用 得到角色基础属性的方法 ,不需要每次都在内存中存一份相同的基础属性。构造方法中将所有需要共享的对象初始化
/// <summary>
/// 享元模式核心
/// </summary>
public class AttrFactory : IAttrFactory
{
//通过角色类型来存储角色共有的属性
private Dictionary<Type, CharacterBaseAttr> mCharacterBaseAttrDict;
private Dictionary<WeaponType, WeaponBaseAttr> mWeaponBaseAttrDict;
/// <summary>
/// 构造方法中将所有需要共享的对象初始化
/// </summary>
public AttrFactory()
{
InitCharacterBaseAttr();
InitWeaponBaseAttr();
}
private void InitWeaponBaseAttr()
{
//初始化字典
mWeaponBaseAttrDict = new Dictionary<WeaponType, WeaponBaseAttr>();
mWeaponBaseAttrDict.Add(WeaponType.Gun, new WeaponBaseAttr("手枪",20, 5, "WeaponGun"));
mWeaponBaseAttrDict.Add(WeaponType.Rifle, new WeaponBaseAttr("长枪",30, 7, "WeaponRifle"));
mWeaponBaseAttrDict.Add(WeaponType.Rocket, new WeaponBaseAttr("火箭",40, 8, "WeaponRocket"));
}
private void InitCharacterBaseAttr()
{
//初始化字典
mCharacterBaseAttrDict = new Dictionary<Type, CharacterBaseAttr>();
mCharacterBaseAttrDict.Add(typeof(SoldierRookie), new CharacterBaseAttr("新手士兵", 80, 2.5f, "RookieIcon", "Soldier3", 0));
mCharacterBaseAttrDict.Add(typeof(SoldierSergeant), new CharacterBaseAttr("中士士兵", 90, 3, "SergeantIcon", "Soldier2", 0));
mCharacterBaseAttrDict.Add(typeof(SoldierCaptain), new CharacterBaseAttr("上尉士兵", 100, 3, "CaptainIcon", "Soldier1", 0));
mCharacterBaseAttrDict.Add(typeof(EnemyElf), new CharacterBaseAttr("小精灵", 100, 3, "ElfIcon", "Enemy1", 0.2f));
mCharacterBaseAttrDict.Add(typeof(EnemyOgre), new CharacterBaseAttr("小精灵", 120, 2, "OgreIcon", "Enemy2", 0.3f));
mCharacterBaseAttrDict.Add(typeof(EnemyElf), new CharacterBaseAttr("巨魔", 200, 1, "TrollIcon", "Enemy3", 0.2f));
}
/// <summary>
/// 得到角色基础属性
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public CharacterBaseAttr GetCharacterBaseAttr(Type t)
{
if (mCharacterBaseAttrDict.ContainsKey(t) == false)
{
Debug.LogWarning("无法根据类型["+t+"]得到角色的基础属性"); return null;
}
return mCharacterBaseAttrDict[t];
}
/// <summary>
/// 得到武器基础属性
/// </summary>
/// <param name="weaponType"></param>
/// <returns></returns>
public WeaponBaseAttr GetWeaponBaseAttr(WeaponType weaponType)
{
if(mWeaponBaseAttrDict.ContainsKey(weaponType) == false