go學習筆記(6)——音樂播放器實現
阿新 • • 發佈:2019-01-05
宣告:首先說明這個專案來自於許式偉的《Go語言程式設計》,書中也給出了詳盡的原始碼描述,不過程式碼中還是存在一些問題,首先說明一下所存在的問題
問題一:音樂的播放結構體中定義了五個屬性欄位,在後面賦值的時候又變成了六個欄位的賦值
問題二:Play函式在呼叫的時候多傳遞了兩個引數,在函式原型的時候只有兩個引數
問題三:RemoveByName方法並沒有實現
這兩個問題應該都是為了後期更好的進行專案擴充套件,不過作為小白的我現在還是以學習和調通程式碼為主,再此基礎上面在進行一步步的功能擴充套件,下面給出響應的專案說明和可以執行的實現基本功能的程式碼實現,所有的實現細節已經給出了詳細的註釋:
一:整體的邏輯框架
二:音樂庫管理模組
》Len 求歌曲名長度
》Get 通過索引查詢歌曲
》Find 通過名字查詢歌曲
》Add 新增歌曲
》Remove 通過索引刪除歌曲
》RemoveByName 通過歌名刪除歌曲
package library import ( "errors" "fmt" ) //定義音樂結構體 type MusicEntry struct { Id string //音樂的唯一Id Name string //音樂名 Artist string //藝術家名 Source string //音樂位置 Type string //音樂型別(MP3和WAV) } type MusicManager struct { musics []MusicEntry } func NewMusicManager() *MusicManager { return &MusicManager{make([]MusicEntry, 0)} } //獲取歌曲的歌名長度 func (m *MusicManager) Len() int { return len(m.musics) } //通過下標獲取歌曲 func (m *MusicManager) Get(index int) (music *MusicEntry, err error) { //未找到時報錯,找到了下標對應的歌曲 if index < 0 || index >= len(m.musics) { return nil, errors.New("Index out of range.") } return &m.musics[index], err } //通過對比名字檢視要找的歌曲是否存在 func (m *MusicManager) Find(name string) *MusicEntry { if len(m.musics) == 0 { return nil } for _, m := range m.musics{ if m.Name == name { return &m } } return nil } //新增歌曲 func (m *MusicManager) Add(music *MusicEntry) { m.musics = append(m.musics, *music) } //通過下標刪除歌曲 func (m *MusicManager) Remove(index int) *MusicEntry { if index < 0 || index > len(m.musics){ return nil } removedMusic := m.musics[index] //從陣列切片中刪除元素 if index < len(m.musics) - 1 { //中間元素 m.musics = append(m.musics[:index - 1], m.musics[index + 1:]...) } return &removedMusic } //通過歌名刪除歌曲 func (m *MusicManager) RemoveByName(name string) *MusicEntry { removedMusic := m.Find(name) if removedMusic == nil{ fmt.Println("Want to delete the song does not exist") return nil } return removedMusic }
二:音樂管理單元測試模組(go單元測試測試將在後面的學習過程在詳細說明,現在只要知道測試的重要性即可)
package library import "testing" func TestOps(t *testing.T) { mm := NewMusicManager() //新建管理測試 if mm == nil { t.Error("NewManagerMusic faild") } if mm.Len() != 0 { //len測試 t.Error("NewManagerMusic faild, not empty") } m0 := &MusicEntry{ "1", "My Heart Will Go On", "Celion Dion", //"Pop", "http://qbox.me/24501234", "Mp3", } mm.Add(m0) //新增測試 if mm.Len() != 1 { t.Error("MusicManager.Add() failed") } m := mm.Find(m0.Name) //find測試 if m == nil { t.Error("MusicManager.Find() failed") } if m.Id != m0.Id || m.Name != m0.Name || m.Artist != m0.Artist || m.Source != m0.Source || m.Type != m0.Type { t.Error("MusicManager.Find() failed. Find item mismatch") } m, err := mm.Get(0) //get測試 if m == nil { t.Error("MusicManager.Get() failed", err) } //空的時候直接進行測試會出問題 m = mm.Remove(0) //Remove測試 if m == nil || mm.Len() != 0 { t.Error("MusicManager.Remove() failed", err) } }
三:播放實現(播放包括的格式有MP3和WAV兩種格式,當然再次也可以擴張使其支援其他格式的播放)
package mp
//音樂播放模組
import "fmt"
//設計一個簡單的介面避免將MusicEntry中多餘的資訊傳入
type Player interface {
Play(Source string)
}
//播放實現,再此也可以在新增其他格式
func Play(Source, mtype string) {
var p Player
switch mtype {
case "MP3": //MP3格式播放
p = &MP3Player{}
case "WAV": //WAV格式播放
p = &WAVPlayer{}
default:
fmt.Println("Unsupported music type", mtype)
return
}
p.Play(Source)
}
package mp
import (
"fmt"
"time"
)
type MP3Player struct {
stat int
progress int
}
//MP3格式播放具體實現
func (p *MP3Player) Play(Source string) {
fmt.Println("Playing MP3 music", Source)
p.progress = 0
for p.progress < 100 {
time.Sleep(100 * time.Millisecond) //假裝正在播放
fmt.Print(".")
p.progress += 10
}
fmt.Println("\nFinished playing", Source)
}
package mp
import (
"fmt"
"time"
)
type MP3Player struct {
stat int
progress int
}
//MP3格式播放具體實現
func (p *MP3Player) Play(Source string) {
fmt.Println("Playing MP3 music", Source)
p.progress = 0
for p.progress < 100 {
time.Sleep(100 * time.Millisecond) //假裝正在播放
fmt.Print(".")
p.progress += 10
}
fmt.Println("\nFinished playing", Source)
}
四:主程式呼叫實現
package main
import (
"goCode/src/music/library"
"fmt"
"strconv"
"goCode/src/music/mp"
"bufio"
"os"
"strings"
)
var lib *library.MusicManager
var id int = 1
//管理模組控制代碼實現
func handleLibCommands(tokens []string) {
switch tokens[1] {
case "list":
for i := 0; i < lib.Len(); i++ {
e, _ := lib.Get(i)
fmt.Println(i + 1, ":", e.Name, e.Artist, e.Source, e.Type)
}
case "add":
if len(tokens) == 6 {
id++
lib.Add(&library.MusicEntry{strconv.Itoa(id),
tokens[2], tokens[3], tokens[4], tokens[5]})
}else {
fmt.Println("USAGE: lib add <name><artist><source><type>")
}
case "remove":
if len(tokens) == 3 {
lib.RemoveByName(tokens[2])
}else {
fmt.Println("USAGE: lib remove <name>")
}
default:
fmt.Println("Unrecognied lib commond:", tokens[1])
}
}
//播放模組控制代碼實現
func handlePlayCommand(tokens []string) {
if len(tokens) != 2 {
fmt.Println("USAGE: play <name>")
return
}
e := lib.Find(tokens[1])
if e == nil {
fmt.Println("The Music", tokens[1], "does not exist")
return
}
mp.Play(e.Source, e.Type)
}
func main() {
//列印操作選單
fmt.Println(`
Enter following commands to control the player:
lib list -- View the existing music lib
lib add <name><artist><source><type> -- Add a music to the music lib
lib remove <name> -- Remove the specified music from the lib
play <name> -- Play the specified music
`)
lib = library.NewMusicManager()
r := bufio.NewReader(os.Stdin)
for{
fmt.Print("Enter Command-> ")
rawLine, _, _ := r.ReadLine()
line := string(rawLine)
//輸入q或者e時退出播放器
if line == "q" || line == "e" {
break
}
tokens := strings.Split(line, " ")
if tokens[0] == "lib" {
handleLibCommands(tokens)
}else if tokens[0] == "play"{
handlePlayCommand(tokens)
}else {
fmt.Println("Unrecognized command:", tokens[0])
}
}
}
五:演示