2018.03.18
author: wills
類
類是抽象的概念,對象是實例,建立類的時候我們把動態對象和靜態屬性都要分析到位
編程 7 原則
單一職責 原則
單一原則表示,一個函數只需要完成自己單一的功能就好了
def add(x, y)
return x + y
比如上面這個加法函數,十分簡潔精煉,功能單一,這就是單一性原則
里氏替換 原則
子類替換父類
當兩個函數的關係是is - a類型時,比如 人–學生;人 – 老師。當需要建立這種對象時,我們可以先寫一個人的父類,然後再去繼承它
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
class Student(Person):
def study(self, course):
return '%s is studing %s' %(self.name, course)
class Teacher(Person):
def teach(self, course):
return '%s is teaching %s' %(self.name, course)
stu = Student('wills', 16)
print(stu.study('math'))
teacher = Teacher('williams', 27)
print(teacher.teach('math'))
#> wills is studing math
#> williams is teaching math
上述程序運行結果見註釋,學生和老師都是繼承了人這個類,所以雖然他們都沒有寫構造函數,但是他們的父類有構造函數,直接調用就好。在這裏我們可以看到,子類 學生 和老師都遠遠比他們的父類 人強大,完全可以單向替換,即子類可以替換父類,但是父類卻不能隨便特換子類
在上面的類中 人 學生 老師都有相同的靜態屬性名字 and 年齡,學生 和 老師又有不同的 動態特徵,那麼這就是這個類的方法。
開閉 原則
依賴倒轉 原則
接口隔離 原則
合成聚合複用 原則
類之間的關係主要分爲繼承,依賴,關聯三種,上面的人與學生之間的關係就是繼承,而比如像汽車與發動機,它們的關係很緊密但是又不能稱發動機就是汽車,這種關係我們稱爲關聯,這種關係的強化體,比如人 與 手,人是主體,主體決定了子體的的生命週期,這個種更強的關聯關係稱爲合成。另外一種關係比如像人與駕照,本身它們之間沒有任何關係,但是人依賴駕照纔可以開車,這種關係稱爲依賴
能用強關聯就不要用繼承
迪米特法則(最少知識原則)
(不要和陌生人講話)
總結
GoF 設計模式
面向對象這純理論的說不好說,還是用例子來說明:例子採用五子棋,就是前天那個例子,不過這次我建立了兩個類,分別是棋盤和棋子類。新增了遊戲重開,悔棋等遊戲內容。所有的內容都加了註釋。
首先我們既然要建立棋盤類,那麼先來想想他的
import pygame
EMPTY = 0
BLACK = 1
WHITE = 2
# 設置3個標籤,表示棋盤是下的棋是黑還是白 還是沒有下
BOARD_COLOR = (125, 95, 25)
BLACK_COLOR = (0, 0, 0)
WHITE_COLOR = (255, 255, 255)
WIN_COLOR = (250, 100, 20)
# 表示4用到的4種顏色的三原色值
class RenjuBoard(object):
# 創建一個棋盤對象,屬性有邊長,每個小方格邊長,顏色,以及棋盤列表表示下棋的位置
def __init__(self, side=600, color=BLACK_COLOR):
self.side = side if side % 15 == 0 else side // 15 * 15
self.grid = self.side // 15
self.color = color
self.boards = [[EMPTY] * 15 for _ in range(15)]
self.is_black = True
def reset(self):
""" 重置,將棋盤恢復初始化 """
for row in range(len(self.boards)):
self.boards[row] = [EMPTY] * 15
def move(self, pos):
# 下棋
if self.grid <= pos[0] <= self.grid * 15 and self.grid <= pos[1] <= self.grid * 15:
col = round((pos[0] - self.grid) / self.grid)
row = round((pos[1] - self.grid) / self.grid)
if self.boards[row][col] == EMPTY:
self.boards[row][col] = BLACK if self.is_black else WHITE
self.is_black = not self.is_black
def take_back(self, piece):
# 悔棋
if len(piece.pieces) == 0:
return
# flag表示被悔棋的那個棋子
flag = piece.pieces.popitem()
for tup in flag:
self.boards[tup[0]][tup[1]] = EMPTY
self.is_black = not self.is_black
break
def draw(self, screen):
# 將棋盤畫出來
for i in range(1, 16):
pygame.draw.line(screen, self.color, (self.grid * i, self.grid), (self.grid * i, self.grid * 15))
pygame.draw.line(screen, self.color, (self.grid, self.grid * i), (self.grid * 15, self.grid * i))
pygame.draw.rect(screen, self.color, (self.grid, self.grid, self.grid * 14, self.grid * 14), 5)
pygame.draw.circle(screen, self.color, (self.grid * 8, self.grid * 8), 5, 0)
pygame.draw.circle(screen, self.color, (self.grid * 4, self.grid * 4), 3, 0)
pygame.draw.circle(screen, self.color, (self.grid * 4, self.grid * 12), 3, 0)
pygame.draw.circle(screen, self.color, (self.grid * 12, self.grid * 4), 3, 0)
pygame.draw.circle(screen, self.color, (self.grid * 12, self.grid * 12), 3, 0)
class Piece(object):
def __init__(self):
self.pos = (0, 0)
self.color = BLACK_COLOR
self.pieces = {}
def reset(self):
# 重置 表示一個棋都沒有下
self.pieces = {}
def move(self, board, pos):
# 下棋,棋子組成一個字典
if board.grid <= pos[0] <= board.grid * 15 and board.grid <= pos[1] <= board.grid * 15:
col = round((pos[0] - board.grid) / board.grid)
row = round((pos[1] - board.grid) / board.grid)
self.pieces.update({(row, col): board.boards[row][col]})
def draw_self(self, screen, board):
# 將字典中所有棋子畫出來
for key in self.pieces:
self.pos = ((key[1] + 1) * board.grid, (key[0] + 1) * board.grid)
self.color = BLACK_COLOR if self.pieces[key] == BLACK else WHITE_COLOR
pygame.draw.circle(screen, self.color, self.pos, board.grid // 2)
def who_win(board):
# 判斷水平方向勝利
for n in range(15):
for num in range(1, 3):
flag = 0
for piece in board.boards[n]:
if piece == num:
flag += 1
if flag == 5:
if num == 1:
return 1
else:
return 2
else:
flag = 0
# 判斷垂直方向勝利
flag = 0
for piece in board.boards:
if piece[n] == num:
flag += 1
if flag == 5:
if num == 1:
return 1
else:
return 2
else:
flag = 0
# 判斷正斜方向勝利
for num in range(1, 3):
for n in range(4, 25):
flag = 0
for i, piece in enumerate(board.boards):
if 0 <= n - i <= 14 and piece[n - i] == num:
flag += 1
if flag == 5:
if num == 1:
return 1
else:
return 2
else:
flag = 0
# 判斷反斜方向勝利
for n in range(10, -10, -1):
flag = 0
for i, piece in enumerate(board.boards):
if 0 <= n + i <= 14 and piece[n + i] == num:
flag += 1
if flag == 5:
if num == 1:
return 1
else:
return 2
else:
flag = 0
return 0
def main():
def refresh():
""" 刷新界面 """
nonlocal board, piece, screen
screen.fill(BOARD_COLOR)
board.draw(screen)
piece.draw_self(screen, board)
pygame.display.flip()
def reset():
""" 遊戲重置 """
nonlocal board, piece, game_over, screen
board.reset()
piece.reset()
screen.fill(BOARD_COLOR)
board.draw(screen)
piece.draw_self(screen, board)
pygame.display.flip()
game_over = False
def show_text(x):
# 顯示勝利或失敗的文本
if x == 1:
x = ' BLACK WIN'
elif x == 2:
x = ' WHITE WIN'
mfont = pygame.font.SysFont('Airal', 64)
mtext = mfont.render('GAME OVER' + x, True, WIN_COLOR)
screen.blit(mtext, (board.grid * 1, board.grid * 7))
pygame.display.flip()
def take_back():
# 悔棋操作
nonlocal board, piece, game_over
board.take_back(piece)
game_over = False
board = RenjuBoard()
piece = Piece()
clock = pygame.time.Clock()
pygame.init()
screen = pygame.display.set_mode((650, 650))
pygame.display.set_caption('五子棋')
game_over = False
# 標籤表示遊戲有沒有結束
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
# 下棋
board.move(event.pos)
piece.move(board, event.pos)
#piece.draw_self(screen, board)
elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
# 悔棋
take_back()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_F1:
# 遊戲重開
reset()
if not game_over:
refresh()
for n in range(1, 3):
if who_win(board) == n:
show_text(n)
game_over = True
clock.tick(24)
pygame.quit()
if __name__ == '__main__':
main()
這個五子棋是我寫的比較完善的五子棋了,一般五子棋遊戲有的操作都有,只是不能提前判斷勝負,必須至少下足夠五顆棋子纔可以