我有一個需要擴展的基本抽象類,它定義了一個唯一的公共方法,該方法使用子類預期的功能。在這里, onlyfullSoundSentence意味著是“公開的”——供外部世界使用。
class Animal {
constructor(nickname){
this.nickname = nickname
}
fullSoundSentence(){
//expects this.composesound to exist
return `${this.nickname} ${this.composesound()}!`
}
}
然后我有很多類擴展它提供一些核心功能(這里他們只是回傳一個字串,但實際上他們需要訪問this,修改物件的屬性等等)
class Dog extends Animal {
doessound(){
return "barks"
}
}
class Cat extends Animal {
doessound(){
return "meows"
}
}
另一個子類家族然后以不同的方式使用此功能。我們使用Dog和Cat功能的一種“模式” 。這些模式提供了抽象基礎方法 ( fullSoundSentence) 所期望的功能,但它們需要是特定的動物。
class LoudAnimal extends Animal {
composesound(){
return `loudly ${this.doessound()}`
}
}
class CalmAnimal extends Animal {
composesound(){
return `calmly ${this.doessound()}`
}
}
現在,貓和狗都可以既平靜又響亮。=任何動物都可以處于任何模式
問:我如何創建一只平靜的狗或一只吵鬧的貓等等?
我可以為每個組合(
CalmDog,LoudDog,CalmCat, ...)手工創建類,但是如果有更多的動物和更多的模式,那就太糟糕了I could make the modes just object with functionalities that the abstract
Animalwould expect as an argument for example, but this is messy, especially if the mode also needs to modify properties and so on
Isn't there some better way?? I'm looking for ways to do this in JavaScript or TypeScript.
uj5u.com熱心網友回復:
下一個提供的方法引入了一個工具集,包括(a)背景關系感知函式和基于函式的 mixin (它們實作了無法通過子型別化的類層次結構以有意義的方式提供的行為)和(b)一個Animal基類,更多特定的動物子型別和工廠,以表明可以在物件創建程序(或物件的生命周期)期間和任何級別的任何時間應用基于 mixin 的組合。
所有實作的功能都源自 OP 的示例代碼,分解和重新組裝,同時保留動物型別特定的屬性和方法名稱。
從最初提供的 OPAnimal和Dog/Cat extends Animal代碼來看,為了證明基Animal類的存在是合理的,并且為了DRY兩個子型別(Dog和Cat),這樣的基本型別不僅要具有它nickname的sound特性,還要具有它的屬性和伴隨的doessound方法。Dog并且Cat兩者都依賴于super委托并且足以提供默認值。
其余的取決于進一步的子型別和混合組合的混合,或者取決于例如實體化類并通過混合組合將特定行為應用于實體的工廠。
這是為什么?
兩行代碼...
class LoudAnimal extends Animal { composesound () { /* ... */ } }
... 和 ...
class CalmAnimal extends Animal { composesound () { /* ... */ } }
……完全沒有意義。
平靜/吵鬧的動物型別不是應該/可以以有意義的方式描述的東西,例如nickname具有sound屬性和doessound方法的物體形式,而狗/貓可以通過這些動物特定的鍵來描述和識別。
但是可能會有吵鬧的狗和/或平靜的貓和/或反之亦然。因此,此型別別需要獲得特定的行為/特征,例如冷靜/大聲或冷靜/大聲表達自己。這就是 mixin 的用途。
// sound-specific functions/methods (behavior) utilized by mixins.
function getBoundBehaviorDrivenSound(behavior) {
// expects `doessound` to exist but does
// handle it forgiving via optional chaining.
return `${ behavior } ${ this?.doessound?.() }`;
}
function getFullSound() {
// expects `nickname` and `composesound` to exist but
// handles the latter forgiving via optional chaining.
return `${ this.nickname } ${ this?.composesound?.() }!`;
}
// sound-specific function-based mixins (applicable behavior).
function withSoundingLoud() {
this.composesound =
getBoundBehaviorDrivenSound.bind(this, 'loudly');
return this;
}
function withSoundingCalm() {
this.composesound =
getBoundBehaviorDrivenSound.bind(this, 'calmly');
return this;
}
function withFullSound() {
this.fullSoundSentence = getFullSound;
return this;
}
// base-class and sub-typing
class Animal {
constructor({
nickname = 'beast',
sound = 'grmpf',
}) {
Object.assign(this, { nickname, sound });
}
doessound() {
return this.sound;
}
}
class Dog extends Animal {
constructor(nickname = 'Buster') {
super({ nickname, sound: 'barks' });
}
}
class Cat extends Animal {
constructor(nickname = 'Chloe') {
super({ nickname, sound: 'meows' });
}
}
// further sub-typing and mixin based composition.
class LoudDog extends Dog {
constructor(nickname) {
super(nickname);
// mixin at creation time at instance/object level.
withSoundingLoud.call(this);
// withFullSound.call(this);
}
}
// factory function featuring mixin based composition.
function createFullySoundingCalmCat(nickname) {
// mixin at creation time at instance/object level.
return withFullSound.call(
withSoundingCalm.call(
new Cat(nickname)
)
);
}
const smokey = createFullySoundingCalmCat('Smokey');
const cooper = new LoudDog('Cooper');
console.log({ smokey, cooper });
console.log('smokey.doessound() ...', smokey.doessound());
console.log('cooper.doessound() ...', cooper.doessound());
console.log('smokey.composesound() ...', smokey.composesound());
console.log('cooper.composesound() ...', cooper.composesound());
console.log('smokey.fullSoundSentence() ...', smokey.fullSoundSentence());
console.log('cooper?.fullSoundSentence?.() ...', cooper?.fullSoundSentence?.());
// ... one more ...
class FullySoundingLoudDog extends LoudDog {
constructor(nickname) {
super(nickname);
}
}
// prototype level aggregation / "class level mixin".
withFullSound.call(FullySoundingLoudDog.prototype);
const anotherDog = new FullySoundingLoudDog;
console.log({ anotherDog });
console.log('anotherDog.doessound() ...', anotherDog.doessound());
console.log('anotherDog.composesound() ...', anotherDog.composesound());
console.log('anotherDog.fullSoundSentence() ...', anotherDog.fullSoundSentence());
.as-console-wrapper { min-height: 100%!important; top: 0; }
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/345014.html
標籤:javascript class inheritance subclass mixins
下一篇:時刻格式回傳“無效日期”
