我希望节省我的时间,并在扩展PIXI类(2d webGl渲染器库)的类之间重用公共代码。
对象接口:
module Game.Core {
export interface IObject {}
export interface IManagedObject extends IObject{
getKeyInManager(key: string): string;
setKeyInManager(key: string): IObject;
}
}
我的问题是getKeyInManager
和setKeyInManager
中的代码不会改变,我想重用它,而不是复制它,这是实现:
export class ObjectThatShouldAlsoBeExtended{
private _keyInManager: string;
public getKeyInManager(key: string): string{
return this._keyInManager;
}
public setKeyInManager(key: string): DisplayObject{
this._keyInManager = key;
return this;
}
}
我想要做的是通过Manager.add()
自动添加管理器中使用的键,以在其属性_keyInManager
中引用对象本身内的对象。
那么,让我们以纹理为例。这里是TextureManager
module Game.Managers {
export class TextureManager extends Game.Managers.Manager {
public createFromLocalImage(name: string, relativePath: string): Game.Core.Texture{
return this.add(name, Game.Core.Texture.fromImage("/" + relativePath)).get(name);
}
}
}
当我做this.add()
时,我希望Game.Managers.Manager
add()
方法调用一个方法,该方法将存在于Game.Core.Texture.fromImage("/" + relativePath)
返回的对象上。这个对象,在这种情况下将是一个Texture
:
module Game.Core {
// I must extends PIXI.Texture, but I need to inject the methods in IManagedObject.
export class Texture extends PIXI.Texture {
}
}
我知道IManagedObject
是一个接口,不能包含实现,但我不知道写什么来在我的ObjectThatShouldAlsoBeExtended
类中注入类Texture
。知道Sprite
,TilingSprite
,Layer
等需要相同的过程。
我需要一个经验丰富的TypeScript反馈/建议,必须可以这样做,但不能通过多次扩展,因为当时只有一个是可能的,我没有找到任何其他解决方案。
TypeScript中有一个鲜为人知的功能,允许您使用Mixins创建可重用的小对象。您可以使用多重继承将这些对象组合成更大的对象(类不允许多重继承,但mixins允许这样做 - 它们与相关实现的接口类似)。
More information on TypeScript Mixins
我认为您可以使用此技术在游戏中的许多类之间共享通用组件,并在游戏中的单个类中重复使用其中的许多组件:
这是一个快速的Mixins演示......首先,你要混合的风味:
class CanEat {
public eat() {
alert('Munch Munch.');
}
}
class CanSleep {
sleep() {
alert('Zzzzzzz.');
}
}
然后是Mixin创建的神奇方法(你只需要在你的程序中的某个地方......)
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
if (name !== 'constructor') {
derivedCtor.prototype[name] = baseCtor.prototype[name];
}
});
});
}
然后你可以创建具有mixin风格的多重继承的类:
class Being implements CanEat, CanSleep {
eat: () => void;
sleep: () => void;
}
applyMixins (Being, [CanEat, CanSleep]);
请注意,此类中没有实际实现 - 足以使其通过“接口”的要求。但是当我们使用这个类时 - 一切正常。
var being = new Being();
// Zzzzzzz...
being.sleep();
我建议使用那里描述的新mixins方法:https://blogs.msdn.microsoft.com/typescript/2017/02/22/announcing-typescript-2-2/
这种方法比Fenton描述的“applyMixins”方法更好,因为自动编译器可以帮助您显示基本和第二继承类的所有方法/属性。
可以在TS Playground site上检查这种方法。
这是实施:
class MainClass {
testMainClass() {
alert("testMainClass");
}
}
const addSecondInheritance = (BaseClass: { new(...args) }) => {
return class extends BaseClass {
testSecondInheritance() {
alert("testSecondInheritance");
}
}
}
// Prepare the new class, which "inherits" 2 classes (MainClass and the cass declared in the addSecondInheritance method)
const SecondInheritanceClass = addSecondInheritance(MainClass);
// Create object from the new prepared class
const secondInheritanceObj = new SecondInheritanceClass();
secondInheritanceObj.testMainClass();
secondInheritanceObj.testSecondInheritance();
不幸的是,typescript不支持多重继承。因此,没有完全无关紧要的答案,您可能需要重新构建您的程序
以下是一些建议:
你必须自己决定你最喜欢哪种方法。我个人建议将类转换为接口。
一个提示:Typescript提供属性,这是getter和setter的语法糖。你可能想看看这个:http://blogs.microsoft.co.il/gilf/2013/01/22/creating-properties-in-typescript/
JavaScript(ES7)中有一个名为装饰器的新功能,使用该功能加上一个名为typescript-mix的小库,你可以使用mixins来获得多个继承,只需几行
// The following line is only for intellisense to work
interface Shopperholic extends Buyer, Transportable {}
class Shopperholic {
// The following line is where we "extend" from other 2 classes
@use( Buyer, Transportable ) this
price = 2000;
}
我认为有一种更好的方法,可以实现稳固的类型安全性和可扩展性。
首先声明要在目标类上实现的接口:
interface IBar {
doBarThings(): void;
}
interface IBazz {
doBazzThings(): void;
}
class Foo implements IBar, IBazz {}
现在我们必须将实现添加到Foo
类。我们可以使用也实现这些接口的类mixin:
class Base {}
type Constructor<I = Base> = new (...args: any[]) => I;
function Bar<T extends Constructor>(constructor: T = Base as any) {
return class extends constructor implements IBar {
public doBarThings() {
console.log("Do bar!");
}
};
}
function Bazz<T extends Constructor>(constructor: T = Base as any) {
return class extends constructor implements IBazz {
public doBazzThings() {
console.log("Do bazz!");
}
};
}
使用类mixins扩展Foo
类:
class Foo extends Bar(Bazz()) implements IBar, IBazz {
public doBarThings() {
super.doBarThings();
console.log("Override mixin");
}
}
const foo = new Foo();
foo.doBazzThings(); // Do bazz!
foo.doBarThings(); // Do bar! // Override mixin