编程语言
首页 > 编程语言> > 游戏编程模式之类型对象模式

游戏编程模式之类型对象模式

作者:互联网

通过创建一个类来支持新类型的灵活创建,其每个实例都代表一个不同的对象类型。

(摘自《游戏编程模式》)

  有两种实现多态的方式,“Have One”和继承。而类型对象模式就是运用“Have One”。类型对象模式的处理和享元模式类似,都是需要将一类对象的共有部分独立成一个类并采用“Have One”将其一一对应起来。两者的区别主要在于:类型对象模式独享一个实例;而享元模式是通过指针共享一个相同实例。

  事实上,类型对象模式的主要目的就是简化继承树的规模。假设我们开发的游戏用100种怪物,每一种怪物都有一个共有的数据部分,如果我们使用继承的方式,将公共数据编写成一个基类Monster,那么我们就需要编写100种怪物类继承Monster!

class Monster{}

class Monster1 : Monster{...}
class Monster2 : Monster{...}
class Monster3 : Monster{...}
class Monster4 : Monster{...}
class Monster5 : Monster{...}
//...

  类型对象模式的代码会将代码组织为如下所示,在类中就没有了继承关系。除此之外,在将怪物共有数据编写成持久化配置文件的时候,我们仅仅需要考虑Monster的序列化即可,如果采用继承将会十分麻烦——我们还需要判断我们要反序列化的Monster数据到底属于的是哪一个子类。

class Monster{}

class Monster1{private:Monster& monster;}
class Monster2{private:Monster& monster;}
class Monster3{private:Monster& monster;}
class Monster4{private:Monster& monster;}
class Monster5{private:Monster& monster;}
//...

类型对象模式

使用情景

相较于使用继承多出的麻烦事

示例

  我们以多个怪物的案例来展示类型对象的代码组织。在一个怪物中,有不同的血量和攻击数值字符串

基础

//怪物种类
class MonsterBreed
{
    public:
        MonsterBreed(double _hp,const char* _attack) : hp(_hp),attack_str(_attack){}
        int GetHeath(){return hp;}
        const char* GetAttack(){return attack_str;}
  
    private:
        double hp;
        char*  attack_str;
}

class Monster
{
    public:
        Monster(MonsterBreed& _breed) : hp(_breed.GetHealth()),breed(_breed){}
        
        const char* GetAttack()
        {
            return breed.GetAttack();
        }
        
        
    private:
        double hp;
        MonsterBreed& breed;
}

让MonsterBreed更像类型

  如何让MonsterBreed更像一个类型呢?类型的作用就是我们可以通过类型实例化一切示例。那么,可以把实例化的功能拥有权给予MonsterBreed类即可。注意的是,我们要把之前提供给Monster的方法隐藏,并通过友元类将他们联系起来。

class MonsterBreed
{
    public:
        MonsterBreed(double _hp,const char* _attack) : hp(_hp),attack_str(_attack){}
        Monster* NewMonster()
        {
            return new Monster(*this);
        }
  
    private:
        int GetHeath(){return hp;}
        const char* GetAttack(){return attack_str;}
        double hp;
        char*  attack_str;
}

class Monster
{
    friend class MonsterBreed;
    
    public:
        Monster(MonsterBreed& _breed) : hp(_breed.GetHealth()),breed(_breed){}
        
        const char* GetAttack()
        {
            return breed.GetAttack();
        }
        
        
    private:
        double hp;
        MonsterBreed& breed;
}

  在NewMonster()方法运用了享元模式,可以创造一类相同 的怪物。但要注意的是,类型对象的值是不能单独修改每一个怪物实例的。(详情查看享元模式的特点)。

在对象类型中实现继承

  上面提到,“类型对象的值是不能单独修改每一个怪物实例”。但是,即使在同一个种类的怪物也存在差别。例如,怪物等级越高,HP可能越高。如何实现呢?我们可以自己手动实现类型对象的继承来解决这个问题。

class MonsterBreed
{
    public:
        MonsterBreed(MonsterBreed* _parent,double _hp,const char* _attack) 
                    :parent(_parent),
                     hp(_hp),
                     attack_str(_attack)
        {
            if(parent!=nullptr)
            {
                if(_hp==0)
                    hp=parent->GetHeath();
                if(_attack==nullptr)
                    attack_str=GetAttack();
            }
        }
                     
        Monster* NewMonster()
        {
            return new Monster(*this);
        }
        
        int GetHeath(){return hp;}
        const char* GetAttack(){return attack_str;}
  
    private:
        double hp;
        char*  attack_str;
        
        MonsterBreed* parent;  //父类节点,也可在GetHeath()\GetAttack编写判断代码来判断是获取当前值还是“父类”的值
}

总结

  类型对象与享元模式(第3章)很接近。它们都让你在实例间共享数据。享元模式倾向于节约内存,并且共享的数据可能不会以实际的“类型”呈现。类型对象模式的重点在于组织性和灵活性。

标签:MonsterBreed,游戏,hp,编程,模式,attack,类型,class,Monster
来源: https://www.cnblogs.com/ZhuSenlin/p/15470709.html