【问题标题】:How to create instances of complex class in a better practice?如何更好地创建复杂类的实例?
【发布时间】:2019-05-04 08:52:54
【问题描述】:

作为一个新手,我正在开发一款游戏,但对创建复杂对象的更好方法感到困惑。此问题可能与 OOP、设计模式和 SOLID 原理有关。对于这些问题,编程语言限制很少。

情况很清楚:

  1. 一艘战舰由一个机身和几个炮塔组成。
  2. 一个炮塔由一个盾牌和几个枪管组成。

背景

我正在使用 Pixi.js 和 TypeScript 开发基于浏览器的 2D 游戏。以下类继承自 Pixi.js 的原生类 Sprite 或 Container,但为了清楚起见,我在下面的代码中省略了这些扩展子句。

代码

我可以简单地想出下面的 Barrel、Shield 和 Body 的代码:(在 TypeScript 中,但与 Java 和 C# 几乎没有区别,不是吗?)

class Barrel {
  constructor(texture, x, y, rotation){
    /*...*/
  }
}
class Shield {
  constructor(texture, x, y, rotation){
    /*...*/
  }
}
class Body {
  constructor(texture, x, y, rotation){
    /*...*/
  }
}

问题来了,炮塔和战舰呢?

粗略地说,1 个炮塔 = 1 个盾牌 + N 个炮管,1 艘战舰 = 1 个车身 + N 个炮塔。

不用再细想,下面的代码就可以轻松搞定:

class Turret {
  private shield: Shield
  private barrels: Barrel[]
  constructor(x, y, rotation, shieldCfg, barrelCfgList) {
    /*...*/
    this.shield = new Shield(shieldCfg.texture, shieldCfg.x, shieldCfg.y, shieldCfg.rotation)
    for(let cfg of barrelCfgList){
      const barrel = new Barrel(cfg.texture, cfg.x, cfg.y, cfg.rotation)
      this.barrels.push(barrel)
    }
  }
}

class Warship {
  private body: Body
  private turrets: Turret[]
  constructor(x, y, rotation, bodyCfg, turretCfgList) {
    /*...*/
    this.body = new Body(bodyCfg.texture, bodyCfg.x, bodyCfg.y, bodyCfg.rotation)
    for(let cfg of turretCfgList){
      const turret = new Turret(cfg.x, cfg.y, cfg.rotation, cfg.shieldCfg, cfg.barrelCfgList)
      this.turrets.push(turret)
    }
  }
}

不难想象 turretCfgList 有多么复杂。

const turretCfgList = [
  {
    x: 1,
    y: 2,
    rotation: 3.14,
    shieldCfg: {
      texture: 'gun-shield'
      x: 4,
      y: 5,
      rotation: 6.28
    },
    barrelCfgList: [
      {
        texture: 'gun-barrel'
        x: 7,
        y: 8,
        rotation: 9.42
      },
      /*...*/
    ]
  },
  /*...*/
]

我的问题是:

  1. 如何解决上面嵌套对象的复杂参数?
  2. 上面的原始代码与工厂方法模式、构建器模式等更好的解决方案有哪些改进?

非常感谢。

我不太确定是否使用下面的代码。仅供参考。

  1. 传递一个复杂的配置对象而不是复杂的参数。
class Turret {
  // constructor(texture, x, y, rotation, shieldCfg, barrelCfgList) {}
  constructor(cfg) {
    /*...*/
    this.shield = new Shield(cfg.shieldCfg.texture, cfg.shieldCfg.x, shieldCfg.y, cfg.shieldCfg.rotation)
    for(let barrelCfg of barrelCfgList){
      const barrel = new Barrel(cfg.barrelCfg.texture, cfg.barrelCfg.x, cfg.barrelCfg.y, cfg.barrelCfg.rotation)
      this.barrels.push(barrel)
    }
  }
}
  1. 在其他地方创建组件实例,并传递这些实例而不是参数
class Turret {
  // constructor(texture, x, y, rotation, shieldCfg, barrelCfgList) {}
  constructor(x, y, rotation, shield, barrels) {
    /*...*/
    this.shield = shield
    this.barrels = barrels
  }
}
  1. 工厂方法模式?
  2. 建造者模式?
  3. ??

    • 更新1,添加一些关于背景的说明。

【问题讨论】:

  • 如果我理解正确,您将使用 TypeScript。但是您将如何进一步使用您的对象?此代码将在浏览器或服务器上运行吗?如果您要使用代码呈现 UI 或开发后端?如果是后端,你将如何与前端通信?等等。所以请描述您的解决方案的架构。
  • @Fyodor 你是对的。我想使用 TypeScript。谢谢你的建议,我会完成你提到的问题的背景。
  • 谢谢。问题变得更清楚了。您的游戏会是多人游戏并会与某些后端通信吗?
  • @Fyodor 目前我没有这样的计划(因为我可能无法处理)。所以这个游戏一开始只是一个单人游戏。实现这一点后,我将尝试实现您介绍的功能。

标签: java c# typescript oop


【解决方案1】:

最好的方法是使用Entity Component System。它是游戏开发的最佳选择,让您有机会将系统的不同部分组合到一个单元/建筑物/其他游戏对象中。您可以使用任何方式来组合它:特定的类、工厂或构建器。

【讨论】:

    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-18
    • 1970-01-01
    相关资源
    最近更新 更多