Swift:闹钟应用多类型Sound变量建模实现咨询
嘿,这个需求太常见啦!用面向对象的多态特性就能完美解决你的两个核心问题——统一获取title,以及根据Sound类型执行不同逻辑。我给你梳理几个实用的建模方案,适配不同的开发场景:
核心思路:抽象统一接口 + 多态实现
首先我们需要定义一个抽象的Sound类型,让Song、Artist、Playlist都实现这个抽象类型,强制它们都提供title属性。这样Alarm类只需要持有这个抽象Sound类型的实例,就能通过alarm.sound.title统一获取标题,完全不用关心具体是哪种类型。
方案1:抽象基类/接口(最通用)
这是所有面向对象语言都支持的基础方案,先定义抽象层,再实现具体子类:
示例代码(Kotlin)
// 抽象基类:定义所有Sound类型必须实现的属性 abstract class Sound { abstract val title: String // 可以添加所有Sound类型通用的方法,比如播放的基础逻辑 } // 具体子类:Song,携带专属属性duration class Song( override val title: String, val duration: Int // 专属属性:歌曲时长(秒) ) : Sound() // 具体子类:Artist,携带专属属性genre class Artist( override val title: String, val genre: String // 专属属性:音乐流派 ) : Sound() // 具体子类:Playlist,携带专属属性songCount class Playlist( override val title: String, val songCount: Int // 专属属性:歌单内歌曲数量 ) : Sound() // Alarm类:依赖抽象的Sound类型,而非具体子类 class Alarm( val triggerTime: String, val sound: Sound ) // 使用示例 val morningAlarm = Alarm("7:30", Artist("周杰伦", "华语流行")) println(morningAlarm.sound.title) // 直接输出:周杰伦
示例代码(Python)
from abc import ABC, abstractproperty # 抽象基类 class Sound(ABC): @abstractproperty def title(self): pass class Song(Sound): def __init__(self, title, duration): self._title = title self.duration = duration @property def title(self): return self._title class Artist(Sound): def __init__(self, title, genre): self._title = title self.genre = genre @property def title(self): return self._title class Playlist(Sound): def __init__(self, title, song_count): self._title = title self.song_count = song_count @property def title(self): return self._title class Alarm: def __init__(self, trigger_time, sound): self.trigger_time = trigger_time self.sound = sound # 使用示例 morning_alarm = Alarm("7:30", Artist("周杰伦", "华语流行")) print(morning_alarm.sound.title) # 输出:周杰伦
方案2:类型分支处理不同逻辑(简单场景首选)
如果你的业务逻辑比较简单,不需要频繁新增Sound类型,直接通过类型检查来执行对应逻辑就足够了,代码直观易懂:
示例代码(Kotlin)
fun playSound(sound: Sound) { when(sound) { is Song -> println("正在播放单曲《${sound.title}》,时长${sound.duration}秒") is Artist -> println("正在播放歌手${sound.title}的热门歌曲,流派:${sound.genre}") is Playlist -> println("正在播放歌单《${sound.title}》,共${sound.songCount}首歌曲") } } // 调用 playSound(morningAlarm.sound)
示例代码(Python)
def play_sound(sound): if isinstance(sound, Song): print(f"正在播放单曲《{sound.title}》,时长{sound.duration}秒") elif isinstance(sound, Artist): print(f"正在播放歌手{sound.title}的热门歌曲,流派:{sound.genre}") elif isinstance(sound, Playlist): print(f"正在播放歌单《{sound.title}》,共{sound.song_count}首歌曲") # 调用 play_sound(morning_alarm.sound)
方案3:访问者模式(复杂逻辑/高扩展性场景)
如果你的业务逻辑非常复杂,或者未来可能频繁新增Sound类型,推荐用访问者模式,把类型相关的逻辑从Sound类中剥离出来,避免大量if/else分支,扩展性更好:
示例代码(Kotlin)
// 定义访问者接口,每个Sound类型对应一个visit方法 interface SoundVisitor { fun visit(song: Song) fun visit(artist: Artist) fun visit(playlist: Playlist) } // 修改抽象基类,添加accept方法 abstract class Sound { abstract val title: String abstract fun accept(visitor: SoundVisitor) } // 子类实现accept方法,把自己传递给访问者 class Song( override val title: String, val duration: Int ) : Sound() { override fun accept(visitor: SoundVisitor) { visitor.visit(this) } } class Artist( override val title: String, val genre: String ) : Sound() { override fun accept(visitor: SoundVisitor) { visitor.visit(this) } } // 实现具体的访问者:播放逻辑 class PlaySoundVisitor : SoundVisitor { override fun visit(song: Song) { println("正在播放单曲《${song.title}》,时长${song.duration}秒") } override fun visit(artist: Artist) { println("正在播放歌手${song.title}的热门歌曲,流派:${song.genre}") } override fun visit(playlist: Playlist) { println("正在播放歌单《${song.title}》,共${song.songCount}首歌曲") } } // 使用示例 val workoutAlarm = Alarm("18:00", Playlist("健身专属", 20)) workoutAlarm.sound.accept(PlaySoundVisitor())
总结
- 如果是简单项目,优先用抽象基类+类型分支,代码简洁易维护;
- 如果项目复杂度高、需要频繁扩展Sound类型,推荐用访问者模式,逻辑分离更清晰;
- 无论哪种方案,核心都是通过抽象统一接口,实现
alarm.sound.title的统一访问,同时利用多态处理不同类型的差异化逻辑。
内容的提问来源于stack exchange,提问作者Travis S.
相关产品推荐
相关产品推荐

