如何按共同特征组织数据? [英] How do I organize data by common traits?

查看:59
本文介绍了如何按共同特征组织数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在对数据进行分类时遇到了麻烦,该方法使我无法通过其公共描述符或特征来引用数据.我很了解继承,特征(编程概念)和接口,但是这些似乎都不是解决我问题的正确方法.

I'm having trouble cataloging data in a way that allows me to reference data by its common descriptors or traits. I'm well aware of inheritance, traits (the programming concept), and interfaces, but none of those seems to be the right answer to my problem.

我正在用JavaScript编写一个程序,该程序可能具有许多不同的项目或对象.假设我的数据类型为WoodenShortSword,我想表示它具有FlammableWeaponOneHanded的特征.然后,我想定义一个仅将同时为OneHandedWeapon的对象作为参数的函数.或者,也许只有FlammableWearable的对象,或者Flammable不是一个Weapon的对象.

I'm writing a program in JavaScript that has potentially many different items or objects. Let's say I have a datatype of WoodenShortSword and I want to express that it has the traits of being Flammable and Weapon and OneHanded. Then, I want to define a function that takes as an argument only objects that are both OneHanded and Weapon. Or, perhaps, only objects that are Flammable and Wearable, or Flammable and not a Weapon.

我该怎么做?

到目前为止,我已经研究了JavaScript和TypeScript中的继承,从技术上讲,继承是可行的,但是由于不允许多重继承,因此需要一堆中间类.类似于FlammableWeaponOneHandedWeapon.这很麻烦,也不理想.

So far, I've looked at inheritance in JavaScript and TypeScript, which would technically work, but would require a bunch of intermediate classes since multiple inheritance isn't allowed. Like FlammableWeapon or OneHandedWeapon. That's cumbersome and not ideal.

我看了TypeScript的抽象类和接口,但更多的是关于共享功能,而不是描述事物.而且,我无法看到内置的方法来检查对象在运行时是否满足接口要求.

I looked at TypeScript's abstract classes and interfaces, but those are more about sharing functionality, not describing things. And there's no built-in way that I could see to check if an object satisfies an interface at runtime.

我还查看了 tcomb 库.尽管像我正在描述的系统是可行的,但它仍然非常麻烦且容易出错.

I also looked at the tcomb library. Although a system like I'm describing is possible, it's still very cumbersome and error-prone.

推荐答案

如果@Manngo的方法还不是解决方案,则可以考虑提供 这个答案需要10到15分钟的阅读时间.它实现了@Manngo的方法,但着重于 解决涉及合成的共同构图冲突 有状态的mixins/特征中的类型.

If @Manngo 's approach is not already the solution, one might consider giving this answer a 10 to 15 min read. It implements @Manngo 's approach but focuses on solving common composition conflicts if it comes to creation of composite types from stateful mixins/traits.

按照OP对所需性状的描述,可以轻松地获得一个 基于功能的混合/特征方法.从而实现细粒度的可组合/可重用 每个单元都描述了一个特定的行为集,这些行为集可以独立发挥作用, 不同的(封装的)数据.

Following the OP's description of the desired traits, one easily could go for a function based mixin/trait approach. Thus implementing fine grained composable/reusable units that each describe a specific behavioral set that acts upon its own and distinct (encapsulated) data.

一个人会实现某种flammableoneHanded行为 通过例如Weapon基类.

One would implement some kind of flammable and oneHanded behavior accompanied by e.g. a Weapon base class.

但是由上述所有内容组成WoodenShortSword并不像 乍一看像人们所期望的那样简单明了.可能有方法 来自oneHandedWeapon的彼此需要采取措施的(封装的) 例如的状态尽快更新武器的isActivated状态,例如 oneHandedtakeInLeftHand方法被调用,或者万一发生签证签证 武器的deactivate动作发生.然后很高兴得到更新 oneHanded的内部isInHand状态.

But composing a WoodenShortSword from all of the above mentioned is not as straightforward as one might expect at first sight. There might be methods from oneHanded and Weapon that need to take action on each others (encapsulated) state for e.g. updating a weapon's isActivated state as soon as an e.g. takeInLeftHand method of oneHanded gets invoked, or visa verce in case a weapon's deactivate action takes place. It then was nice getting updated the inner isInHand state of oneHanded.

一种可靠的方法是方法修改,该方法必须依靠 样板代码上的代码,除非有一天JavaScript本身实现 Function.prototype[around|before|after|afterReturning|afterThrowing|afterFinally].

A reliable approach for this is method modification that has to rely on boilerplate code, unless JavaScript at one day natively implements Function.prototype[around|before|after|afterReturning|afterThrowing|afterFinally].

再有一个更长的示例代码作为概念证明,可能看起来像这样……

A longer example code as proof of concept then might look like this one ...

function withFlammable() {                                // composable unit of reuse (mixin/trait/talent).
  var
    defineProperty = Object.defineProperty,

    isInFlames = false;

  defineProperty(this, 'isFlammable', {
    value:      true,
    enumerable: true
  });
  defineProperty(this, 'isInFlames', {
    get: function () {
      return isInFlames;
    },
    enumerable: true
  });
  defineProperty(this, 'catchFire', {
    value: function catchFire () {
      return (isInFlames = true);
    },
    enumerable: true
  });
  defineProperty(this, 'extinguish', {
    value: function extinguish () {
      return (isInFlames = false);
    },
    enumerable: true
  });
}


function withOneHanded() {                                // composable unit of reuse (mixin/trait/talent).
  var
    defineProperty = Object.defineProperty,

    isInLeftHand = false,
    isInRightHand = false;

  function isLeftHanded() {
    return (isInLeftHand && !isInRightHand);
  }
  function isRightHanded() {
    return (isInRightHand && !isInLeftHand);
  }
  function isInHand() {
    return (isInLeftHand || isInRightHand);
  }

  function putFromHand() {
    return isInHand() ? (isInLeftHand = isInRightHand = false) : (void 0);
  }

  function takeInLeftHand() {
    return !isInLeftHand ? ((isInRightHand = false) || (isInLeftHand = true)) : (void 0);
  }
  function takeInRightHand() {
    return !isInRightHand ? ((isInLeftHand = false) || (isInRightHand = true)) : (void 0);
  }
  function takeInHand() {
    return !isInHand() ? takeInRightHand() : (void 0);
  }

  function switchHand() {
    return (
         (isInLeftHand && ((isInLeftHand = false) || (isInRightHand = true)))
      || (isInRightHand && ((isInRightHand = false) || (isInLeftHand = true)))
    );
  }

  defineProperty(this, 'isOneHanded', {
    value: true,
    enumerable: true
  });

  defineProperty(this, 'isLeftHanded', {
    get: isLeftHanded,
    enumerable: true
  });
  defineProperty(this, 'isRightHanded', {
    get: isRightHanded,
    enumerable: true
  });
  defineProperty(this, 'isInHand', {
    get: isInHand,
    enumerable: true
  });

  defineProperty(this, 'putFromHand', {
    value: putFromHand,
    enumerable: true,
    writable: true
  });

  defineProperty(this, 'takeInLeftHand', {
    value: takeInLeftHand,
    enumerable: true,
    writable: true
  });
  defineProperty(this, 'takeInRightHand', {
    value: takeInRightHand,
    enumerable: true,
    writable: true
  });
  defineProperty(this, 'takeInHand', {
    value: takeInHand,
    enumerable: true,
    writable: true
  });

  defineProperty(this, 'switchHand', {
    value: switchHand,
    enumerable: true
  });
}


function withStateCoercion() {                            // composable unit of reuse (mixin/trait/talent).
  var
    defineProperty = Object.defineProperty;

  defineProperty(this, 'toString', {
    value: function toString () {
      return JSON.stringify(this);
    },
    enumerable: true
  });
  defineProperty(this, 'valueOf', {
    value: function valueOf () {
      return JSON.parse(this.toString());
    },
    enumerable: true
  });
}


class Weapon {                                            // base type.
  constructor() {
    var
      isActivatedState = false;

    function isActivated() {
      return isActivatedState;
    }

    function deactivate() {
      return isActivatedState ? (isActivatedState = false) : (void 0);
    }
    function activate() {
      return !isActivatedState ? (isActivatedState = true) : (void 0);
    }

    var
      defineProperty = Object.defineProperty;

    defineProperty(this, 'isActivated', {
      get: isActivated,
      enumerable: true
    });

    defineProperty(this, 'deactivate', {
      value: deactivate,
      enumerable: true,
      writable: true
    });
    defineProperty(this, 'activate', {
      value: activate,
      enumerable: true,
      writable: true
    });
  }
}


class WoodenShortSword extends Weapon {                   // ... the
  constructor() {                                         // inheritance
                                                          // part
    super();                                              // ...

    withOneHanded.call(this);                             // ... the
    withFlammable.call(this);                             // composition
                                                          // base
    withStateCoercion.call(this);                         // ...

    var                                                   // ... the method modification block ...
      procedWithUnmodifiedDeactivate  = this.deactivate,
      procedWithUnmodifiedActivate    = this.activate,

      procedWithUnmodifiedPutFromHand = this.putFromHand,
      procedWithUnmodifiedTakeInHand  = this.takeInHand,

      procedWithUnmodifiedTakeInLeftHand  = this.takeInLeftHand,
      procedWithUnmodifiedTakeInRightHand = this.takeInRightHand;

    this.deactivate = function deactivate () {            // "after returning" method modification.
      var
        returnValue = procedWithUnmodifiedDeactivate();

      if (returnValue === false) {
          procedWithUnmodifiedPutFromHand();
      }
      return returnValue;
    };
    this.activate = function activate () {                // "after returning" method modification.
      var
        returnValue = procedWithUnmodifiedActivate();

      if (returnValue === true) {
          procedWithUnmodifiedTakeInHand();
      }
      return returnValue;
    };

    this.putFromHand = function putFromHand () {          // "after returning" method modification.
      var
        returnValue = procedWithUnmodifiedPutFromHand();

      if (returnValue === false) {
          procedWithUnmodifiedDeactivate();
      }
      return returnValue;
    };
    this.takeInHand = function takeInHand () {            // "after returning" method modification.
      var
        returnValue = procedWithUnmodifiedTakeInHand();

      if (returnValue === true) {
          procedWithUnmodifiedActivate();
      }
      return returnValue;
    };

    this.takeInLeftHand = function takeInLeftHand () {    // "before" method modification.
      if (!this.isInHand) {
          procedWithUnmodifiedActivate();
      }
      return procedWithUnmodifiedTakeInLeftHand();
    };
    this.takeInRightHand = function takeInRightHand () {  // "before" method modification.
      if (!this.isInHand) {
          procedWithUnmodifiedActivate();
      }
      return procedWithUnmodifiedTakeInRightHand();
    };
  }
}


var
  sword = new WoodenShortSword;

console.log('sword : ', sword);
console.log('(sword + "") : ', (sword + ""));
console.log('sword.valueOf() : ', sword.valueOf());
console.log('\n');

console.log('sword.isFlammable : ', sword.isFlammable);
console.log('sword.isInFlames : ', sword.isInFlames);
console.log('\n');
console.log('sword.isOneHanded : ', sword.isOneHanded);
console.log('sword.isLeftHanded : ', sword.isLeftHanded);
console.log('sword.isRightHanded : ', sword.isRightHanded);
console.log('sword.isInHand : ', sword.isInHand);
console.log('\n');
console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');

console.log('sword.deactivate : ', sword.deactivate);
console.log('sword.activate : ', sword.activate);
console.log('\n');
console.log('sword.deactivate() : ', sword.deactivate());
console.log('sword.activate() : ', sword.activate());
console.log('sword.activate() : ', sword.activate());
console.log('\n');

console.log('sword.isFlammable : ', sword.isFlammable);
console.log('sword.isInFlames : ', sword.isInFlames);
console.log('\n');
console.log('sword.isOneHanded : ', sword.isOneHanded);
console.log('sword.isLeftHanded : ', sword.isLeftHanded);
console.log('sword.isRightHanded : ', sword.isRightHanded);
console.log('sword.isInHand : ', sword.isInHand);
console.log('\n');
console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.switchHand() : ', sword.switchHand());
console.log('\n');

console.log('sword.isLeftHanded : ', sword.isLeftHanded);
console.log('sword.isRightHanded : ', sword.isRightHanded);
console.log('sword.isInHand : ', sword.isInHand);
console.log('\n');
console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.takeInRightHand() : ', sword.takeInRightHand());
console.log('\n');

console.log('sword.isLeftHanded : ', sword.isLeftHanded);
console.log('sword.isRightHanded : ', sword.isRightHanded);
console.log('sword.isInHand : ', sword.isInHand);
console.log('\n');
console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.putFromHand() : ', sword.putFromHand());
console.log('\n');

console.log('sword.isLeftHanded : ', sword.isLeftHanded);
console.log('sword.isRightHanded : ', sword.isRightHanded);
console.log('sword.isInHand : ', sword.isInHand);
console.log('\n');
console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.takeInLeftHand() : ', sword.takeInLeftHand());
console.log('\n');

console.log('sword.isLeftHanded : ', sword.isLeftHanded);
console.log('sword.isRightHanded : ', sword.isRightHanded);
console.log('sword.isInHand : ', sword.isInHand);
console.log('\n');
console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.deactivate() : ', sword.deactivate());
console.log('\n');

console.log('sword.isLeftHanded : ', sword.isLeftHanded);
console.log('sword.isRightHanded : ', sword.isRightHanded);
console.log('sword.isInHand : ', sword.isInHand);
console.log('\n');
console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.activate() : ', sword.activate());
console.log('\n');

console.log('sword.isLeftHanded : ', sword.isLeftHanded);
console.log('sword.isRightHanded : ', sword.isRightHanded);
console.log('sword.isInHand : ', sword.isInHand);
console.log('\n');
console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.switchHand() : ', sword.switchHand());
console.log('\n');

console.log('sword.isFlammable : ', sword.isFlammable);
console.log('sword.isInFlames : ', sword.isInFlames);
console.log('\n');
console.log('sword.isLeftHanded : ', sword.isLeftHanded);
console.log('sword.isRightHanded : ', sword.isRightHanded);
console.log('sword.isInHand : ', sword.isInHand);
console.log('\n');
console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.catchFire() : ', sword.catchFire());
console.log('\n');

console.log('sword.isFlammable : ', sword.isFlammable);
console.log('sword.isInFlames : ', sword.isInFlames);
console.log('\n');

console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.extinguish() : ', sword.extinguish());
console.log('\n');

console.log('sword.isFlammable : ', sword.isFlammable);
console.log('sword.isInFlames : ', sword.isInFlames);
console.log('\n');

console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');


console.log('sword.putFromHand() : ', sword.putFromHand());
console.log('\n');

console.log('sword.isActivated : ', sword.isActivated);
console.log('\n');

.as-console-wrapper { max-height: 100%!important; top: 0; }

这篇关于如何按共同特征组织数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆