關於python的class對象的建立

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()

這個五子棋是我寫的比較完善的五子棋了,一般五子棋遊戲有的操作都有,只是不能提前判斷勝負,必須至少下足夠五顆棋子纔可以

最後忠告一句,要想面向對象的好,我覺得前期就是要多寫,瘋狂的寫,只要不斷地練習,才能真正的掌握面向對象的精髓。但是不要每次都寫一樣的,需要不斷地提高難度,讓自己不斷地突破。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章