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()
这个五子棋是我写的比较完善的五子棋了,一般五子棋游戏有的操作都有,只是不能提前判断胜负,必须至少下足够五颗棋子才可以