简体   繁体   English

是否可以从另一个类内部调用一个类(没有扩展)?

[英]Is it possible to call a class from inside another class (without extending)?

I'm working on different components for a basic game. 我正在为基本游戏开发不同的组件。

Right now my structure is I have a file of race classes that get exported to another file where I have a class that extends off of the Human race and makes a Player. 现在我的结构是我有一个种族类的文件,它被导出到另一个文件,在那里我有一个类,它延伸到人类并制造一个玩家。 Giving the Player both the attributes of a Human and a Player. 为玩家提供人类和玩家的属性。

However, this means that if I wanted to make a Player that wasn't Human I would have to make a new class of Player that extends off of a different race. 然而,这意味着如果我想制作一个不是人类的玩家,我将不得不制作一个新的玩家类别,而不是一个不同的种族。 That seems like poor practice and I want to find a way to refactor it all to make it flow better. 这似乎是糟糕的做法,我想找到一种方法来重构它以使其更好地流动。


Here is my Human class: 这是我的人类课程:

export class Human {
constructor() {
    this.type = 'Human';
    this.health = 10;
    this.baseAttack = 2;
    this.baseDefense = 1;
}

And here is my player Player class: 这是我的播放器播放器类:

export class Player extends Human {
constructor(name, level){
    super();
    var inventory = {};
    this.name = name;
    this.level = level;
    this.inventory = inventory;
    this.currentCapacity = 0;
    this.maxCapacity = 50;
}

There's other functions in the Player class related to the inventory however those don't seem relevant to my problem. Player类中还有与库存相关的其他功能,但这些功能似乎与我的问题无关。


My intended results are that I have a group of races that when I make a Player or a Character I can select from that group and then that Player or Character will inherit attributes that are static to that race (Eg health, baseAttack, and baseDefense). 我的预期结果是我有一组种族,当我制作一个玩家或角色时,我可以从该组中选择,然后该玩家或角色将继承该种族的静态属性(例如health,baseAttack和baseDefense) 。

As the smart kids say, prefer composition to inheritance. 正如聪明的孩子所说,更喜欢作文和继承。 You could do something like this without deviating too far from your current approach: 你可以做这样的事情而不偏离现有的方法:

class Orc {
  constructor() {
    this.mortal = true
  }
}

class Player {
constructor(race, name, level){
    var inventory = {};
    this.race = race;
    this.name = name;
    this.level = level;
    this.inventory = inventory;
    this.currentCapacity = 0;
    this.maxCapacity = 50;
    }
}

const orc = new Player(new Orc(), 'Baz', 1 )
console.log(orc.race)

There are a lot of other ways to skin this cat, including having Human descend from Player. 还有很多其他方法可以让这只猫受到伤害,包括让人类从玩家身上下来。 In fact, that would be the usual way to model those entities using classical inheritance (Player is general case and Humans and Orcs are more specific). 事实上,这将是使用经典继承对这些实体进行建模的常用方法(Player是一般情况,人类和兽人更具体)。

class PlayerClassic {
constructor(name, level){
    var inventory = {};
    this.name = name;
    this.level = level;
    this.inventory = inventory;
    this.currentCapacity = 0;
    this.maxCapacity = 50;
    }
}


class Human extends PlayerClassic {
  constructor(name, level) {
    super(name, level)
    this.mortal = true
  }
}

const human = new Human('Johnny', 2)
console.log(human)

I find inheritance hierarchies seldom buy much advantage. 我发现继承层次结构很少有利可图。 And in both of the above cases you have to use typeof to determine what sort of creature you're dealing with. 在上述两种情况下,你都必须使用typeof来确定你正在处理什么类型的生物。

If it was my code, I'd probably skip the classes entirely. 如果是我的代码,我可能会完全跳过这些课程。 I might do something like the following to build up a data structure that represented a constructed player: 我可能会做类似以下的事情来构建一个表示构造的玩家的数据结构:

const raceTemplates = {
  human: {mortal:true}, 
  elf: { mortal:true}}

const playerMaker = template => (race, name, level)=> {
  return {
    name,
    level,
    race,
    inventory: {},
    currentCapacity:0,
    maxCapacity:50,
    ...template[race]
  }
}  

const player = playerMaker(raceTemplates)('elf', 'sammy', 2)
console.log(player) 

Here's a link to a repl.it for anyone who is interested: 以下是对任何感兴趣的人的repl.it链接:

https://repl.it/@rmoskal/RealisticWholeParameter https://repl.it/@rmoskal/RealisticWholeParameter

To answer your question in the title: 要在标题中回答您的问题:

Can a class contain another class? 一个类可以包含另一个类吗?

Yes, it can. 是的,它可以。

Otherwise, for your scenarios, I see race as an attribute (similarly player can have qualities too, that may require setting). 否则,对于您的场景,我将race视为一种属性(类似的玩家也可以具有品质,可能需要设置)。 Therefore I would suggest injecting values through a factory method. 因此,我建议通过工厂方法注入值。 Just a simple highlight provided, but you can work a more structured factory method on your own. 只是提供了一个简单的亮点,但您可以自己使用更结构化的factory method

function raceFactory(raceName) {
    if (raceName == 'raceA') {
        let res = new Human();
        res.health = 30;
        return res;
    }
}

and in the main app: 并在主应用程序中:

let humanRaceA = new factory.RaceFactory('raceA');

Here's another solution 这是另一种解决方案

function Player(name, level){
    var inventory = {};
    this.name = name;
    this.level = level;
    this.inventory = inventory;
    this.currentCapacity = 0;
    this.maxCapacity = 50;
}

module.exports.Player = function(race, name, level){
  var newPlayer = Object.create(Object.assign(race.prototype, Player.prototype))//override  
  race.call(newPlayer);
  Player.call(newPlayer, name, level);
  return newPlayer;
}

And in client code you can do something like: 在客户端代码中,您可以执行以下操作:

var { Player } = require(/* your module */)
var newPlayer = Player(Human, 'Bob', 23);
console.log(newPlayer);
/*
{ type: 'Human',
  health: 10,
  baseAttack: 2,
  baseDefense: 1,
  name: 'Bob',
  level: 23,
  inventory: {},
  currentCapacity: 0,
  maxCapacity: 50 }
*/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM