带有类但没有 Mixins 的 Javascript 中的组合模式?

Posted

技术标签:

【中文标题】带有类但没有 Mixins 的 Javascript 中的组合模式?【英文标题】:Composition Pattern in Javascript with Classes but without Mixins? 【发布时间】:2021-11-09 19:48:39 【问题描述】:

以下是在 javascript 中实现组合模式的有效策略吗?我想使用类而不是构造函数或普通对象,而且我知道 Mixins 不是最佳实践。一个问题是,在这种方法中,添加到Person 对象的方法没有附加到原型,因此每个方法都需要内存分配。谢谢!

class Person 
  name;
  constructor(name) 
    this.name = name;
  


function fly() 
  return 
    fly() 
      console.log(`$this.name can fly!`);
    ,
  ;


function swim() 
  return 
    swim() 
      console.log(`$this.name can swim!`);
    ,
  ;


function makeFlyingPerson(name) 
  return Object.assign(new Person(name), fly());


function makeSwimmingPerson(name) 
  return Object.assign(new Person(name), swim());

【问题讨论】:

不过,这仍然是 mixins。您将两个对象混合在一起 - 一个对象的方法/属性被添加到另一个对象。 如果它按照您想要的方式工作,它就是有效的。也就是说,我认为flyswim 等没有任何理由成为函数,正如@VLAZ 指出的那样,这个 is 混合。说到:“而且我知道 Mixins 不是最佳实践” 为什么不呢?根据谁? 如果您使用 Class 语法的动机是为了简化 Java 和 JavaScript 之间的大脑切换,我建议您的代码对于试图理解这一点的 Java 开发人员来说会非常混乱。如果这是您的目标,那么请一直使用 Class 语法,以便其他人可以轻松掌握它。 FWIW。 @r_zelazny ... 对于提供的示例,任何 mixin 支持技术只有在 OP 实际上不希望每个人实例具有飞行和游泳行为/特征时才有意义。否则Person.prototype 仍然是分配此类行为的最佳位置。在这种情况下,稍后通过将所需行为直接混入原型中来增强已经实现的Person 类的原型是完全有效的。 【参考方案1】:

...添加到Person 对象的方法未附加到原型,因此每个方法都需要分配内存

没错,但这是一个微不足道的数量,每个对象每个方法的一个属性的成本(保存该方法的函数引用)。属性不是什么都没有,但它们并不大。为免生疑问:function 对象被所有实例重用,而不是复制。

flyswim 没有理由成为函数,但(至少,从问题中看不出),直接使用对象:

class Person 
    name;
    constructor(name) 
        this.name = name;
    


const flyMethods = 
    fly() 
        console.log(`$this.name can fly!`);
    ,
;

const swimMethods = 
    swim() 
        console.log(`$this.name can swim!`);
    ,
;

function makeFlyingPerson(name) 
    return Object.assign(new Person(name), flyMethods);


function makeSwimmingPerson(name) 
    return Object.assign(new Person(name), swimMethods);

请注意,这仍然使用 mixins(您的原始版本和上述版本)。

除非您打算将fly/flyMethodsswim/swimMethodsPerson 以外的其他类一起重用,否则使用extends 似乎更简单,并且会给您提供原型方法重用:

class FlyingPerson extends Person 
    fly() 
        // ...
    


如果您正在在多个类中重用fly/flyMethods 等,另一种选择是使用工厂构建函数从各种方法集创建原型,然后重复使用它:

class Person 
    name;
    constructor(name) 
        this.name = name;
    


const flyMethods = 
    fly() 
        console.log(`$this.name can fly!`);
    ,
;

const swimMethods = 
    swim() 
        console.log(`$this.name can swim!`);
    ,
;

function extendWith(cls, name, ...mixins) 
    // We use the wrapper object so that the class constructor's name is assigned from `name`
    const obj = 
        [name]: class extends cls 
        
    ;
    Object.assign(obj[name].prototype, ...mixins);
    return obj[name];


const FlyingPerson = extendWith(Person, "FlyingPerson", flyMethods);
const SwimmingPerson = extendWith(Person, "SwimmingPerson", swimMethods);
const FlyingSwimmingPerson = extendWith(Person, "FlyingSwimmingPerson", flyMethods, swimMethods);

const joe = new FlyingSwimmingPerson("Joe");
joe.fly();
joe.swim();

class Animal 
    name;
    type;
    constructor(name, type) 
        this.name = name;
        this.type = type;
    


const FlyingSwimmingAnimal = extendWith(Animal, "FlyingSwimmingAnimal", flyMethods, swimMethods);

console.log(FlyingSwimmingAnimal.name); // FlyingSwimmingAnimal
const splippery = new FlyingSwimmingAnimal("Slippery");
splippery.fly();
splippery.swim();

【讨论】:

我想知道 OP 问题中的这一点。哪一点对 OP 更重要 - 开发人员沟通或内聚/最小耦合。 如果应该增强对象,这些函数会更有意义,例如,flyer = obj => obj.fly = fly。然后允许一个人制作flier(person) 甚至swimmer(flier(person)) 来获得两者。当然,只有对象,这可以是Object.assign(person, swimMethods, flyMethods) 感谢您的回答! @r_zelazny - 我的荣幸!我已将其添加到 FWIW 的末尾。编码愉快!

以上是关于带有类但没有 Mixins 的 Javascript 中的组合模式?的主要内容,如果未能解决你的问题,请参考以下文章

scss 带有mixins的Bootstrap断点。

无法在带有打字稿的 vue 中使用 Mixins

通过 mixins 处理带有自定义 slug 的重复对象

我可以交叉编译可选择使用 Java 8 中的类但编译为 Java 6 的 Java 代码吗?

有没有更好的方法或在 vue.js 中导入 mixins

JavaScrip对象