Javascript 组合/继承/工厂-这种情况下的最佳模式
好[你每天的时间] 今天我学习了javascript(es6)中的合成和工厂函数。我理解这一点,并同意这一点(至少在javascript中)。然后,我意识到我有一种情况,我应该使用作文 问题一: 有没有一种方法可以改变我复杂的、继承的结构,使类由函数组成,而不必使用数量惊人的装饰器?我是否错过了关于作文的一些东西(我觉得我错过了) 处境 我有一个基类音频播放器:Javascript 组合/继承/工厂-这种情况下的最佳模式,javascript,inheritance,design-patterns,composition,Javascript,Inheritance,Design Patterns,Composition,好[你每天的时间] 今天我学习了javascript(es6)中的合成和工厂函数。我理解这一点,并同意这一点(至少在javascript中)。然后,我意识到我有一种情况,我应该使用作文 问题一: 有没有一种方法可以改变我复杂的、继承的结构,使类由函数组成,而不必使用数量惊人的装饰器?我是否错过了关于作文的一些东西(我觉得我错过了) 处境 我有一个基类音频播放器: class BaseAudioPlayer { public track; protected seekBar;
class BaseAudioPlayer {
public track;
protected seekBar;
public togglePlay() {
//
}
public seek(time) {
//some seek methods using this.seekBar
}
}
class MainAudioPlayer{
constructor(){
this.basePlayerComponent=new BasePlayerComponent();
}
public loadTrack(track) {
//This is horrible
this.track = track;
}
public setSeekBar(seekBar) {
//This is horrible
this.seekBar = seekBar
}
public togglePlay() {
this.basePlayerComponent.togglePlay();
}
public seek(time) {
this.basePlayerComponent.seek(time);
}
}
一些玩家的职业会从这里扩展如下:
class MainAudioPlayer extends BaseAudioPlayer {
public loadTrack(track) {
//This is horrible
this.track = track;
}
public setSeekBar(seekBar) {
//This is horrible
this.seekBar = seekBar
}
}
请记住,我实际上在父类和子类中有更多的方法,在一些子类中有很多方法,而在其他子类中没有。当然,不涉及多重继承,但我看到在某些情况下,可能会有多个相似的子玩家(糟糕!)
我可以使用许多装饰器,如@playable()
@seekable()
等。但后来我发现,最终,混合的数量会变得巨大。我想我也可以以类似的方式使用工厂函数,但看到了相同的问题
完全公开:我正在使用Angular2,并大量缩减了代码,以保留关于使用哪种设计模式的讨论,而不是关于特定框架中的实现
更新1:
正如@JocelynLecomte所评论的,我的问题可能不清楚
- MainAudioPlayer(和其他播放器)继承自BaseAudioPlayer,因为所有音频播放器必须具有
、切换播放
,以及一些其他方法(特定于angular2,因此此处不包括)搜索
- 目前,有三个类继承自BaseAudioPlayer:MainAudioPlayer、DetailAudioPlayer和CardAudioPlayer。将来可能会有更多,而且每个人都有自己的具体方法
- 继承用于避免重复,所有玩家都是BaseAudio玩家。但是,所有玩家都有
和切换播放
方法搜索
- 我想使用合成,因为我可以看到一个玩家将来可能没有
方法或类似的方法seek
- 似乎使用组合会在所有玩家类中产生大量的锅炉板代码,我希望避免这种情况
- 可能有许多装饰器(
,@playable
)@seakable
- 可以使用基本玩家服务(如@amuse的回答)并具有冗余方法
- 可能有许多装饰器(
为OP的给定场景找到最合适的合成方法,实际上取决于数据被认为是如何隐藏和访问的。当然,基础架构应该是基础/子类型(类、继承)和基于函数的混合的良好组合 因此,下一个给定示例代码所示的方法是OP在
BaseAudioPlayer
中提供的直接结果,公共曲目
和受保护的seekBar
。更改这些属性的可见性和读写访问权限将对所有类和混合类的重构方式产生重大影响
这是我到目前为止的想法
function with trackmanagement(stateValue){//可组合的细粒度行为重用单元(mixin/trait)。
变量
defineProperty=Object.defineProperty;
//写入受保护的“track”值。
功能加载轨道(轨道){
返回(stateValue.track=track);
}
//公共“loadTrack”方法(写访问)。
定义属性(这是“加载轨道”{
值:loadTrack,
可枚举:true
});
}
带有seekbar(stateValue){//可组合的细粒度行为重用单元(mixin/trait)的函数。
变量
defineProperty=Object.defineProperty;
//写入受保护的'seekBar'值。
功能设置seekBar(seekBar){
返回(stateValue.seekBar=seekBar);
}
//public`setSeekBar`方法(写访问)。
定义属性(此“设置seekbar”{
值:setSeekBar,
可枚举:true
});
}
类BaseAudioPlayer{//基本类型。
构造函数(stateValue){
变量
defineProperty=Object.defineProperty;
//正在读取受保护的“track”值。
函数getTrack(){
返回stateValue.track;
}
函数togglePlay(){
//
}
函数寻道(时间){
//一些使用`stateValue.seekBar的seek方法`
}
//受公共保护的“track”值(读访问)。
定义属性(此“轨迹”{
get:getTrack,
可枚举:true
});
//公共“togglePlay”方法。
定义属性(这是“togglePlay”{
值:切换播放,
可枚举:true
});
//公共“搜索”方法。
定义属性(此“seek”{
价值观:寻求,
可枚举:true
});
}
}
类MainAudioPlayer扩展了BaseAudioPlayer{//复合类型…扩展了具有mixin/trait组合的类。
构造函数(stateValue){
状态值=(
((stateValue!=null)&&(typeof stateValue==“object”)&&stateValue)
|| {}
);
超级(状态值);
withTrackManagement.call(this,stateValue);
使用seekbar.call(this,stateValue);
}
}
var mainPlayer=(新的mainpaudioplayer);
日志(“mainPlayer:”,mainPlayer);
console.log(“mainPlayer.track:”,mainPlayer.track);
log(“(mainPlayer.track='foobar'):”,(mainPlayer.track='foobar');
console.log(“mainPlayer.track:”,mainPlayer.track);
console.log(“mainPlayer.loadTrack('favorit track'):”,mainPlayer.loadTrack('favo