举例来巩固一下前面学习的成果,让我们来实现播放器的播放列表(SongList):
append(song)→ list 为list添加一首歌,添加在首位置,并且返回这个list delete_first()→ song 删除第一首歌,并返回这首歌 delete_last()→ song 删除最后一首歌,并返回这首歌 [index]→ song 工具index来返回一种index指定的song with_title(title)→ song 通过song的title,反正这个指定的song |
我们可以看到,SongList可以在首位置添加一首歌,可以删除首位置的一首歌,可以删除末位的一首歌,由此我们应该是用dequeue这个数据结构来实现这个功能:
dequeue:double ended queue
这些本不是ruby的内容,但是我相信大家应该不会为此而吝惜时间,stacks,queues,dequeues都是有序排列成的,这个区别于sets的一个重要特点,hashes也是无序的,所谓的无序是items或者说elements的顺序
1)stack:LIFO,后进先出,进入方式是压栈,从top压入,出栈弹出最上item
2)queue:FIFI,先进先出,进入方式是从bottom进入,出栈弹出最上的item
3)dequeue:前后(top,bottom)都可以进出item
继续我们的implementing SongList之旅
ruby里面提供了丰富的方法,在对于array这个class时,提供了一些方法,使得这个array变成一个stack,queue或者dequeue,这样的方式比java灵活,使用java如何实现?用interface,这就使得我们必须去关心实现。利用array我们可以实现很多功能
initialize:
class SongList
def initialize
@songs = Array.new
end
end
这里为SongList建立一个用于保存song的array
append:
class SongList
def append(song)
@songs.push(song) #push为array尾部添加一个element
self #同于return self ,self 表示返回一个自己(这个method所在的class)的object,这里就是SongList的object
end
end
这里希望大家不要去思考array class 的method到底是把array变成了什么样的数据结构,只要关系这个method对array做了什么事情,就可以了
delete:
class SongList
def delete_first
@songs.shift
end
def delete_last
@songs.pop
end
end
下面是特殊的方法:[]
class SongList
def [](index) #定义[]方法,使用这样的规则
@songs[index]
end
end
对于array methods总结:
methods | parameters | return |
push | all | array |
shift | 无 | obj or nil |
pop | 无 | obj or nil |
shift删除数组第一个element,然后返回这个element
pop删除数组最后一个element,然后返回这个element
最后说明一下:ClassName#method_name 这说明class有method_name 这个method,比如:
Array#shift 这个说明Array这个class有shift这个method。在你参考library或者一些文章的时候,可能看到这样的表达,这里告诉大家一下
我们实现到这里,不想再做复杂的实现过程,现在学习任何测试:
Unit testing:ruby为我们提供了一个testing framework,在这个framework里面有2个比较重要的方法:
assert_equal:带2个parameters,判断这2个parameters是不是相等,假如不相等,产生failures
assert_nil:带1个parameter,判断这个parameter是不是nil,假如不等于nil,产生failures
代码:
require 'test/unit'
class TestSongList < Test::Unit::TestCase
def test_delete
list = SongList.new
s1 = Song.new('title1','artist1',1)
s2 = Song.new('title2','artist2',2)
s3 = Song.new('title3','artist3',3)
s4 = Song.new('title4','artist4',4)
list.append(s1).append(s2).append(s3).append(s4)
assert_equal(s1,list[0])
assert_equal(s3,list[2])
assert_nil(list[9])
assert_equal(s1,list.delete_first)
assert_equal(s2,list.delete_first)
assert_equal(s4,list.delete_last)
assert_equal(s3,list.delete_last)
assert_nil(list.delete_last)
end
end
完整代码下载
测试正确:
-------------------------------------------------------
Loaded suite D:/Ruby-1
Started
.
Finished in 0.0 seconds.
1 tests, 8 assertions, 0 failures, 0 errors
-------------------------------------------------------
出错:
-------------------------------------------------------
Loaded suite D:/Ruby-1
Started
F
Finished in 0.03 seconds.
1) Failure:
test_delete(TestSongList) [D:/Ruby-1.rb:47]:
<#<Song:0x2ba9fe4 @artist="artist3", @no=3, @title="title3">> expected but was
<#<Song:0x2ba9fa8 @artist="artist4", @no=4, @title="title4">>.
1 tests,6 assertions, 1 failures, 0 errors
-------------------------------------------------------
这里给出信息得到在第7个assertion处出现了问题,注意不需要使用new产生TestSongList,直接运行就好了,因为test包含了initial housekeeping,它会通知ruby,要使用TestUnit framework,并且告诉framework我们已经写了测试代码