MicroPython物件導向程式設計

不同於傳統程序式導向的程式設計方式把程式碼和要處理的資料分開對待,在物件導向程式設計的觀念中,是以資料為中心的處理方式,先思考要解決的問題需要哪些資料結構,接著設計處理這個資料的方法,提供外部一-個介面用來存取這些資料,讓解決問題的過程更加地聚焦在要解決的資料上。

以移動的汽車為例,假設我們要設計一個由玩家控制的汽車物件,這台汽車只能在第4列(別忘了是從0開始數)中移動,一開始建立此物件時要設定它的初始位置,在產生這個物件的實例之後即會把自己畫在指定的位置上,並接受程式指令move_left和move_right,讓自己向左移動1格或是向右移動一格。

依據上述的定義,把這個汽車類別叫做Car,它需要儲存的資料結構只有pos和old這兩個變數,也就是記錄自己的x座標(y座標已固定在第4列上),一開始的類別定義如下:

class Car():
def __init__(self, pos=2):
self.pos = pos
self.old = pos
display.set_pixel(self.pos, 4, 9)

在這個類別定義中,__init__是初始化函數,每一個類別定義都要有一個,而在此函數的參數列表中,self是固定一定要有的參數,它的後面則是依需求在決定,而在這個例子中,我們加上一個pos參數,讓此類別在建立的時候可以指定汽車一開始的位置,如果在建立此物件時沒有指定pos的話,則預設是在2的地方。

第3行的地方設定self.pos = pos,第4行的地方設定self.old = pos,也就是讓一開始的新舊位置都指定物件建立時所在的位置,方便之後的移動效果(也就是在移動到新的位置時,要把舊的位置的車子刪除)。第5行利用set_pixel點亮車子所在的位置,示意出車子的外觀。

有了初始化的操作也知道目前車子的位置之後,接下來要有一個move_left和move_right的函數,讓程式可以指揮車子向左移動或向右移動,這兩個函數的內容如下:

def move_right(self):
if self.pos < 4:
self.pos += 1
self.draw()
def move_left(self):
if self.pos > 0:
self.pos -= 1
self.draw()

同學們有沒有發現,其實它們的作用就是被呼叫之後,先檢查自己的位置的範圍是否已經到了左邊界或是右邊界了,如果還沒有的話,就依照函數的方向,把self.pos加1或是減1。不管是向右移動或是向左移動,因為位置已經有所改變了,因此就呼叫self.draw函數來把舊位置的亮點刪除,並在新位置上點亮LED,程式如下所示:

def draw(self):
if self.pos != self.old:
display.set_pixel(self.old, 4, 0)
display.set_pixel(self.pos, 4, 9)
self.old = self.pos

在程式中先檢查是否舊位置和新位置真的有所不同,如果是相同的,在同一個位置上熄滅一個LED並把它點亮只會造成閃爍而已。如果新舊位置是不同的,就可以先把舊位置的LED熄滅,在新位置上點亮它的LED,最後在第5行的地方更新新舊位置為一致。

有了這幾個基本函數,這個汽車類別就夠用了,不過,在這個例子中,我們還多提供了一個函數讓程式可以傳回目前汽車的位置,方便除錯之用,get_pos函數如下:

def get_pos(self):
return self.pos

在定義了汽車Car類別之後,如何主程式中使用呢?我們直接來看完整的程式例:

from microbit import *
class Car():
def __init__(self, pos=2):
self.pos = pos
self.old = pos
display.set_pixel(self.pos, 4, 9)
def get_pos(self):
return self.pos
def draw(self):
if self.pos != self.old:
display.set_pixel(self.old, 4, 0)
display.set_pixel(self.pos, 4, 9)
self.old = self.pos
def move_right(self):
if self.pos < 4:
self.pos += 1
self.draw()
def move_left(self):
if self.pos > 0:
self.pos -= 1
self.draw()
if __name__ == '__main__':
car = Car(3)
while True:
if button_a.was_pressed():
car.move_left()
sleep(100)
elif button_b.was_pressed():
car.move_right()
sleep(100)

主程式從第29行開始,第29行產生一個物件的執行實例叫做car,它的預設位置是在第4列的第3行(3, 4),在進入無窮迴圈之後,第31行偵測按鈕A是否被按下過,如果有的話,就把汽車往左移動,請看第32行物件導向程式在呼叫物件方法函數的寫法,第34行到第36行也是類似的方式,只不過它偵測的是按鈕B。

同學們應該可以發現,有了Car類別之後,在主程式中就可以透過精簡的語法來執行汽車的動畫功能,這是物件導向程式設計法最厲害的地方之一喔。

同樣使用類別定義,接下來我們來看看飛彈類別Missile:

class Missile():
def __init__(self, x, y):
self.x = x
self.y = y
self.oldx = x
self.oldy = y
display.set_pixel(x, y, 9)
def fire(self):
for i in range(self.y, -1, -1):
display.set_pixel(self.x, self.oldy, 0)
display.set_pixel(self.x, i, 9)
self.oldy = i
sleep(300)
display.set_pixel(self.x, self.oldy, 0)