1、模式标准
模式名称:亨元模式
模式分类:结构型
模式意图:运用共享技术有效地支持大量细粒度的对象
结构图:
适用于:
1、一个应用程序使用了大量的对象.
2、完全由于使用大量的对象,造成很大的存储开销。
3、对象的大多数状态都可变为外部状态。
4、如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
5、应用程序不依赖于对象标识。由于 Flyweight 对象可以被共享,所以对于概念上明显有别的对象,标识测试将返回真值。
2、分析与设计
亨元模式和对象池模式有点像,但是有差别,对象池模式在我们前面提到的抽象工厂中,有提到部分代码,对象池模式一般有回收这个动作,回收对象一般会通过reset方法进行重置。而亨元模式不涉及reset回收,它是对大量颗粒度对象的共享技术。
前面在访问者模式中,我们简单设计了一个伤害系统,但是每次创建伤害访问者时都需要new一个,比如一次单体普通攻击:new MonomerAttackVisitor(100),但伤害事件在游戏中是大量存在,每次都new一个肯定是不友好的。这就需要将伤害值作为外部状态从对象中剥离出来,然后通过亨元模式将相同对象的共享起来。
结合前面的攻击访问者,重新描述一下意图:
意图:运用共享技术有效地支持大量细粒度的(攻击访问者)对象
3、开始打造
攻击访问者
export interface IAttackVisitor {
// 普通单位
visitUnitItem(unitItem: IUnitItem, damage: number): void
// 英雄单位
visitHeroUnitItem(unitItem: IUnitItem, damage: number): void
}
// 单体攻击
export class MonomerAttackVisitor implements IAttackVisitor {
// 普通单位
visitUnitItem(unitItem: IUnitItem, damage: number): void {
console.log('普通单位扣减 hp=' + damage)
unitItem.subHp(damage)
}
// 英雄单位,受到伤害值为0.8
visitHeroUnitItem(unitItem: IUnitItem, damage: number): void {
console.log('英雄单位扣减 hp=' + damage)
unitItem.subHp(damage * 0.8)
}
}
// 群体攻击
export class GroupAttackVisitor implements IAttackVisitor {
// 普通单位
visitUnitItem(unitItem: IUnitItem, damage: number): void {
unitItem.subHp(damage)
// todo 周围单位也受到伤害
}
// 英雄单位,受到伤害值为0.8
visitHeroUnitItem(unitItem: IUnitItem, damage: number): void {
unitItem.subHp(damage * 0.8)
// todo 周围单位也受到伤害
}
}
亨元工厂
// 亨元工厂
export class AttackVisitorFlyweightFactory {
private flyweights: { [key: string]: IAttackVisitor } = {};
public getFlyweight(key: string): IAttackVisitor {
if (!this.flyweights[key]) {
switch (key) {
case 'monomer':
this.flyweights[key] = new MonomerAttackVisitor();
break;
case 'group':
this.flyweights[key] = new GroupAttackVisitor();
break;
// 添加其他 AttackVisitor 类型的处理逻辑
default:
throw new Error('Invalid AttackVisitor type');
}
}
return this.flyweights[key];
}
}
4、开始使用
将攻击访问者工厂加入到全局单例里面
export class SingletonInstance {
// 设计模式5(单例模式)
private static _instance: SingletonInstance = new this()
static get instance(): SingletonInstance {
return this._instance
}
static getInstance() {
return this._instance
}
// game: TCSGame
game: JCQGame
// game: DemoGame
// game: FeijianGame
.....
// 攻击访问者工厂
attackVisitor: AttackVisitorFlyweightFactory = new AttackVisitorFlyweightFactory()
}
通过外观模式加入到xhgame中
export class xhgame {
// 设计模式10(外观模式)
....
// 攻击访问者工厂
static get attackVisitor() {
return gameInstance.attackVisitor
}
}
修改单位里面的attack方法
export class UnitItem extends Component implements IItem, IUnitItem {
ad: number = 100;
mp: number = 0;
role: Fighter;
private currentState: IUnitState = null;
......
accept(visitor: IAttackVisitor, damage: number) {
visitor.visitUnitItem(this, damage)
}
attack(unitItem: UnitItem<T>) {
if (!this.canAttack()) {
// 不能处理攻击的逻辑,可能是显示消息或者进入其他状态
return;
}
// 尝试进入攻击状态
this.getCurrentState().attack()
let damage = this.ad
let attackVisitor = xhgame.attackVisitor.getFlyweight('monomer')
// let attackVisitor = new MonomerAttackVisitor(damage)
unitItem.accept(attackVisitor, damage) // 伤害作为外部参数传入
}
}