混入(mixin)

混入(mixin)

JavaScript 不允许多继承,但是可以通过混入 (mixin)技术来组合其他类的方法。在 JavaScript 中混入的本质其实还是原型委托调用。

假如有一个星球类 Planet,我们想让他拥有另一个 Circle 类的方法和属性,但是这个类本身已经继承了 Component 类,这时就可以使用混入技术:

1
2
3
4
@ccclass('Planet')
export class Planet extends Component {
private _level: number = 2
...

创建一个混入函数 mixinCircle 并导出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { Vec3 } from 'cc'

type Constructor<T = {}> = new (...args: any[]) => T

export interface ICircle {
position: Vec3
radius: number
}

export const mixinCircle = <TBase extends Constructor>(Base: TBase) => {
return class Circle extends Base implements ICircle {
protected _radius!: number
private _position!: Vec3

constructor(...args: any[]) {
super(...args)
this.intersect.bind(this)
}

/**
* @en The position of the circle, which is a Vec3 vector
* @zh 圆的直径,是一个 Vec3 向量
*/
get position() {
return this._position
}

/**
* @en The radius of the circle
* @zh 圆的半径
*/
get radius() {
return this._radius
}

/**
* @en Determines if it intersects with another circle
* @zh 判断是否与另外一个圆相交
*/
public intersect(circle: ICircle) {
return Vec3.distance(this.position, circle.position) < this.radius + circle.radius
}
}
}

这时候再修改 Planet 类,让他继承混入 Circle 类的 Component 类即可。

1
2
3
4
@ccclass('Planet')
export class Planet extends mixinCircle(Component) {
private _level: number = 2
...

如果我们想要混入多个类以上这个方法还可以嵌套使用,如:

1
2
3
4
@ccclass('Planet')
export class Planet extends mixinNode(mixinCircle(Component)) {
private _level: number = 2
...