1、模式标准

模式名称:访问者模式

模式分类:行为型

模式意图:将数据操作与数据结构分离,使得在不修改数据结构的前提下,可以添加或改变对数据的操作。

结构图:

用23种设计模式打造一个cocos creator的游戏框架----(九)访问者模式-LMLPHP

适用于:

  1. 当你需要对一个复杂对象结构执行一些操作,并且你希望实现这些操作与该对象结构的类无关时。访问者模式使得你可以在不修改现有类的情况下添加新的操作。

  2. 当你需要清洁并且有逻辑的方式来操作复杂的对象结构时。将相关的操作逻辑放在一个访问者类中,使得你可以将复杂的操作逻辑与数据结构的类分离。

  3. 当你需要在不同的类上执行类似的操作,而不希望污染这些类的接口时。访问者模式允许你在不影响其他类的情况下添加新的操作。

2、分析与设计  

访问者模式,简单描述就是一个访问者访问了你,对你提了一些建议和操作。这里打个比方,比如本来你只会发1234567乐符发音,音乐老师访问者过来说,听他的指挥,你说好的(accept),之后你就听从音乐老师的指挥,哼出了一个曲调。老师一走,你就啥都不会了。

在游戏设计中,不确定其他人是如何用这个访问者模式的,但是我的第一感觉是是否能用在攻击上面,比如单位A对单位B发动了一个火球攻击,火球在遇到单位B时,对其产生了伤害。这个火球只是一个特效,火球的伤害就是伤害访问者。

来问一下GPT是如何说的

会破坏封装?什么意思,继续问

“这句话有些不理解,“可能会破坏被访问元素的封装””

你有什么好的建议吗?

class Unit {
    constructor(health, armor) {
        this.health = health;
        this.armor = armor;
    }

    accept(visitor) {
        visitor.visitUnit(this);
    }

    decreaseHealth(amount) {
        this.health -= amount;
    }

    increaseArmor(amount) {
        this.armor += amount;
    }
}

class AttackVisitor {
    constructor(damage) {
        this.damage = damage;
    }

    visitUnit(unit) {
        unit.decreaseHealth(this.damage);
        // 更复杂的攻击逻辑可以在这里添加
    }
}

let unit = new Unit(100, 50);
let attackVisitor = new AttackVisitor(10);
unit.accept(attackVisitor);

总得来说的是可行的方案。

意图:将数据操作(伤害操作)与数据结构(受攻击者)分离,使得在不修改数据结构(受攻击者)的前提下,可以添加或改变对数据的操作(伤害操作)。

3、开始打造

用23种设计模式打造一个cocos creator的游戏框架----(九)访问者模式-LMLPHP

import { IUnitItem } from "../items/IItem"

export interface IAttackVisitor {
    // 普通单位
    visitNormalUnitItem(unitItem: IUnitItem): void
    // 英雄单位
    visitHeroUnitItem(unitItem: IUnitItem): void
}

 

import { IUnitItem } from "../items/IItem";
import { IAttackVisitor } from "./IAttackVisitor";

// 单体攻击
export class MonomerAttackVisitor implements IAttackVisitor {
    damage: number = 0
    constructor(damage: number) {
        this.damage = damage
    }
    // 普通单位
    visitUnitItem(unitItem: IUnitItem): void {
        unitItem.subHp(this.damage)
    }
    // 英雄单位,受到伤害值为0.8
    visitHeroUnitItem(unitItem: IUnitItem): void {
        unitItem.subHp(this.damage * 0.8)
    }
}

 

import { IUnitItem } from "../items/IItem";
import { IAttackVisitor } from "./IAttackVisitor";

// 群体(衍射)攻击
export class GroupAttackVisitor implements IAttackVisitor {
    damage: number = 0
    constructor(damage: number) {
        this.damage = damage
    }
    // 普通单位
    visitUnitItem(unitItem: IUnitItem): void {
        unitItem.subHp(this.damage)
        // todo 周围单位也受到伤害
    }
    // 英雄单位,受到伤害值为0.8
    visitHeroUnitItem(unitItem: IUnitItem): void {
        unitItem.subHp(this.damage * 0.8)
        // todo 周围单位也受到伤害
    }
}
export interface IUnitItem {
    hp: number
    subHp(hp: number): void
    accept(visitor: IAttackVisitor): void
}
export class UnitItem extends Component implements IItem, IUnitItem {

    accept(visitor: IAttackVisitor) {
        visitor.visitUnitItem(this)
    }


}

4、开始使用 

export class UnitItem  extends Component implements IItem, IUnitItem {

    ad: number = 100;

    accept(visitor: IAttackVisitor) {
        visitor.visitUnitItem(this)
    }

    attack(unitItem: UnitItem) {
        let damage = this.ad
        let attackVisitor = new MonomerAttackVisitor(damage)
        unitItem.accept(attackVisitor)
    }

}
let unitItem001 = xhgame.itemFactory.createUnitItem('shibing_001')
let unitItem002 = xhgame.itemFactory.createUnitItem('shibing_002')

unitItem001.attack(unitItem002)

有了访问者模式后,伤害管理变得更简单,目前只是简单版本,后续还得继续完善

12-12 05:33