JavaScript中不使用Mixin仅用类实现组合模式的方案是否有效?
问题解答
你给出的方案属于轻量级的能力混入实现,不是严格意义上的组合模式实现,且你担心的内存问题确实存在:
- 你通过
Object.assign将fly、swim方法直接拷贝到每个Person实例的自身属性上,每创建一个实例就会生成一份独立的方法副本,实例数量较多时会造成不必要的内存浪费。 - 本质上该方案还是Mixin模式的变种,不符合你想要规避Mixin、使用类实现的诉求。
符合要求的优化方案
方案1:类工厂实现原型级组合(继承式组合)
该方案所有能力方法都会挂载到类的原型上,所有实例共享方法副本,没有内存浪费问题,全程基于类实现:
class Person { name; constructor(name) { this.name = name; } } // 定义能力类 class Flyable { fly() { console.log(`${this.name} can fly!`); } } class Swimmable { swim() { console.log(`${this.name} can swim!`); } } // 组合类工厂:将多个能力类的原型方法合并到基类的子类原型上 function createComposedClass(baseClass, ...abilityClasses) { class Composed extends baseClass {} abilityClasses.forEach(abilityClass => { Object.getOwnPropertyNames(abilityClass.prototype).forEach(prop => { if (prop !== 'constructor') { Composed.prototype[prop] = abilityClass.prototype[prop] } }) }) return Composed } // 生成组合后的业务类 const FlyingPerson = createComposedClass(Person, Flyable) const SwimmingPerson = createComposedClass(Person, Swimmable) // 支持多能力组合 const FlyingSwimmingPerson = createComposedClass(Person, Flyable, Swimmable) // 调用示例 const p1 = new FlyingPerson('张三') p1.fly() // 输出:张三 can fly! const p2 = new FlyingSwimmingPerson('李四') p2.swim() // 输出:李四 can swim!
方案2:纯组合模式实现(对象委托,无继承)
完全遵循经典组合模式「对象组合优于类继承」的设计原则,方法同样共享无内存浪费,灵活性更高,支持运行时动态增减能力:
class Person { name; constructor(name) { this.name = name; } } // 能力类,不直接继承Person,通过持有Person实例实现逻辑调用 class FlyAbility { constructor(person) { this.person = person } fly() { console.log(`${this.person.name} can fly!`) } } class SwimAbility { constructor(person) { this.person = person } swim() { console.log(`${this.person.name} can swim!`) } } // 组合容器类 class ComposedPerson { constructor(name, abilities = []) { this.person = new Person(name) // 实例化传入的能力,挂载到当前实例 this.abilities = abilities.map(Ability => new Ability(this.person)) // 把能力方法代理到容器实例上,直接调用即可 this.abilities.forEach(ability => { const proto = Object.getPrototypeOf(ability) Object.getOwnPropertyNames(proto).forEach(prop => { if (prop !== 'constructor' && !this[prop]) { this[prop] = (...args) => ability[prop](...args) } }) }) } } // 调用示例 const f1 = new ComposedPerson('张三', [FlyAbility]) f1.fly() // 输出:张三 can fly! const s1 = new ComposedPerson('李四', [FlyAbility, SwimAbility]) s1.swim() // 输出:李四 can swim!
内容的提问来源于stack exchange,提问作者r_zelazny
相关产品推荐
相关产品推荐

