【问题标题】:What are flexible approaches for creating different kinds or types of shape objects like rect- or triangles?创建不同种类或类型的形状对象(如矩形或三角形)的灵活方法是什么?
【发布时间】:2021-11-02 03:38:14
【问题描述】:

我有这段代码 sn-p 可以创建一个盒子数组,我想让它成为通用的,以便它也可以,例如,存储一个三角形。我不太确定我需要使用哪些参数或者我需要如何修改它以便它允许一个三角形。如果我想要三角形和盒子,创建一个三角形数组然后将它们定位成一个盒子似乎会更好,但是我会失去创建简单矩形的灵活性。上下文:这是一个实现 z 缓冲区的程序的 sn-p。

class Box {
  /** @member {Object} position of the box storing x,y,z coordinates */
  position;
  /** @member {Object} size of the box storing width and height */
  size;
  /** @member {Object} color of the box given in RGB */
  color;

  constructor (props) {
    this.position = props.position;
    this.size = props.size;
    this.color = props.color;
  }

  /**
   * Check if given point is in box
   * @param {Number} px coordinate of the point
   * @param {Number} py coordinate of the point
   * @return {Boolean} point in box
   */
  pointInBox (px,py) {
    return this.position.x < px && this.position.x + this.size.width > px
        && this.position.y < py && this.position.y + this.size.height > py;
  }
}

const boxes = [
  new Box({
    position: { x: 50, y: 50, z: 10 },
    size: { width: 150, height: 50 },
    color: { r: 255, g: 0, b:0 }
  }),
  new Box({
    position: { x: 80, y: 30, z: 5 },
    size: { width: 10, height: 150 },
    color: { r: 0, g: 255, b:0 }
  }),
  new Box({
    position: { x: 70, y: 70, z: 8 },
    size: { width: 50, height: 40 },
    color: { r: 0, g: 0, b: 255 }
  })       
];

console.log({ boxes });
.as-console-wrapper { min-height: 100%!important; top: 0; }

【问题讨论】:

  • 使 what 通用?它只是一个数组;为什么不能给它加三角形?
  • 不应该一个盒子也有length,让它实际上是3维的吗?毕竟它有 x、y 和 z 坐标。如果不是,那么它是一个矩形而不是一个盒子。如果打算使用 3D 形状,那么您的意思可能是 Tetrahedron 而不是三角形?

标签: javascript inheritance factory composition es6-class


【解决方案1】:

使用 vanilla JS,您必须使用继承,如下所示。我会推荐使用 Typescript,它是 Javascript 的超级集合,它使使用类型变得更加容易。

class Shape {
  constructor({ color, position}){
    this.color = color;
    this.positon = position;
  }
}

class Cube extends Shape {
  constructor({color, position, height, width, length}){
    super({ color, position });
    this.height = height;
    this.width = width;
    this.length = length;
  }
}

const myCube = new Cube({
  color: "#555555",
  position: {x: 12, y: 5, z: 9},
  height: 12,
  width: 12,
  length: 12
});

console.log(myCube)

在 Typescript 中,它看起来像这样:

interface Coordinate {
    x: number;
    y: number;
    z: number;
}

interface Shape {
    color: string;
    position: Coordinate;
}

interface Box extends Shape {
    height: number;
    width: number; 
    length: number;
}

现在,如果我想要一个适用于盒子和形状的函数,你可以这样做:

function getPosition(shape:Shape){
    return shape.position;
}

const myShape: Box = {
  color: "red",
  position: {
    x: 1,
    y: 4,
    z: 7,
  },
  height: 12,
  length: 12,
  width: 12,
};

getPosition(myShape);

因为 Box 扩展了形状,该功能适用​​于它们,以及任何其他扩展形状的接口。

这只是你可以用 Typescript 做的事情的皮毛。

【讨论】:

  • 有趣。我没有意识到可以在 JS 中应用 OOP 类型继承。所以我可以有一个扩展 Shape 的三角形类;我如何与 JS 沟通以绘制三角形而不是正方形或矩形?以前,我使用这种格式进行绘制:0、1、-1、-1、1、-1,而不仅仅是 x、y;但是,对于 z 缓冲区,我需要我所看到的 x、y、z 格式的三角形。
  • 如果您使用 3d 形状,您首先需要创建一个可以渲染任何 2d 形状的函数,因为 3D 形状是 2d 平面的集合。然后您可以渲染任何 3d 形状,而不必担心它是什么形状。任何二维形状也是如此。当我有空时,我会用一个例子添加另一个答案。
【解决方案2】:

使用 Vanilla-JS 的原因之一不仅限于一个选项,例如选择基于继承的方法。组合,基于定制的 mixin,确实提供/支持 OP 正在寻找的灵活性。

一个也没有在哪里(以及何时甚至如何)组合,例如在简单的对象级别,例如工厂函数或在类构造函数中的实例化时。

// function based "position" mixin.
function withPosition({ x = 0, y = 0, z = 0 }) {

  // "position" specifc (default) assignment.
  Object.assign(this, { position: { x, y, z } });
}

// function based "shape" mixin.
function asShape({ color='#000', ...position }) {

  // "shape" specifc (default) assignment.
  Object.assign(this, { color });
  
  // delegate "position" specific assignement
  // and default handling to the mixin.
  withPosition.call(this, (position || {}));
}


// factory function.
function createRectangle({ width=10, height=10, ...options }) {
  const type = {};
  
  // delegate "shape" specific assignements
  // and default handling to the mixin.
  asShape.call(type, options);

  // "rectangle" specifc assignments including defaults.
  return Object.assign(type, { width, height });
}

// factory function.
function createCube({ length=10, ...options }) {
  // composition via ...
  // ... "rectangle" specifc forwarding ...
  // ............. and "cube" specific `length` enrichment.
  return { ...createRectangle(options), length }
}

class Cube {
  // `Cube` type instantiation.
  constructor({ width=10, height=10, length=10, ...options }) {;

    // delegate "shape" specific assignements
    // and default handling to the mixin.
    asShape.call(this, options);

    // "cube" specifc assignments including defaults.
    Object.assign(this, { width, height, length });
  }/*
  constructor({ length=10, ...options }) {
    Object.assign(this, { ...createRectangle(options), length });
  }*/
}

const my1stRectangle = createRectangle({
  x: 50,
  y: 50,
  z: 10,
  width: 150,
  height: 50,
  color: '#fc0',
});
const my2ndRectangle = createRectangle({});

const myCubeComposite = createCube({
  x: 50,
  y: 50,
  z: 50,
  color: '#c0f',
});
const myComposedCubeType = new Cube({});

console.log({
  my1stRectangle,
  my2ndRectangle,
  myCubeComposite,
  myComposedCubeType,
});

console.log(
  '(myCubeComposite instanceof Cube) ?',
  (myCubeComposite instanceof Cube)
);
console.log(
  '(myComposedCubeType instanceof Cube) ?',
  (myComposedCubeType instanceof Cube)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

【讨论】:

  • @KillerSheltie ...查看一个灵活的、仅 vanilla-js 且无需继承的方法。
猜你喜欢
  • 1970-01-01
  • 2013-04-20
  • 1970-01-01
  • 2022-07-22
  • 1970-01-01
  • 2019-05-20
  • 1970-01-01
  • 1970-01-01
  • 2012-07-27
相关资源
最近更新 更多