赞
踩
如果子类的某个方法要根据情况,来决定用什么类去实例化相关对象,可以考虑工厂方法模式。此模式可以单独使用,也可以再无法预知对象类型的时候使用,例如待初始化的对象类型要从文件中读入或者由用户输入。
参照书上例子,根据用户的调用,创建国际跳棋或者国际象棋的棋盘。
引入相关模块
import io
import itertools
import os
import sys
import tempfile
import unicodedata
定义棋盘常量
#跳棋、棋盘背景类型
BLACK, WHITE = ("BLANK", "WHITE")
#国际象棋,棋子类型
DRAUGHT, PAWN, ROOK, KNIGHT, BISHOP, KING, QUEEN = ("DRAUGHT", "PAWN",
"ROOK", "KNIGHT", "BISHOP", "KING", "QUEEN")
最顶层调用代码
if __name__ == "__main__":
main()
def main():
checkers = CheckersBoard()
print(checkers)
chess = ChessBoard()
print(chess)
根据平台定义控制台输出
if sys.platform.startswith("win"):
def console(char, background):
return char or " "
sys.stdout = io.StringIO()
else:
def console(char, background):
return "\x1B[{}m{}\x1B[0m".format(
43 if background == BLACK else 47, char or " ")
补充知识点
python 继承的实现:
一种是如上篇文章说的使用
class absClass(mateclass=abc.ABCMeta)
一种是在文档中直接说明
书上这个例子用到的方法:
凡是需要有子类重新实现的方法都抛出NotImplementedError异常。
抽象棋盘父类的实现:
class AbstractBoard:
def __init__(self,rows,columns):
#创建一个rows行columns列的二维列表,并将元素初始化None
#[[列1,列2,列3,.....],
#[列1,列2,列3,.....],
#[列1,列2,列3,.....],
# .....
#]
self.board = [[None for _ in range(columns)] for _ in range(rows)]
#通过工厂方法populate_board()来实例化棋子
self.populate_board()
#定义工厂方法,由子类来实现,创建棋盘对象
def populate_board(self):
raise NotImplementedError()
#打印棋盘,将由子类调用
def __str__(self):
squares = []
for y,row in enumerate(self.board):
for x, piece in enumerate(row):
square = console(piece, BLANK if(y + x) % 2 else WHILE)
squares.append("\n")
return "".join(squares)
知识点补充 itertools 模块小结
http://www.wklken.me/posts/2013/08/20/python-extra-itertools.html
itertools.islice(iterable,start,stop,step):对迭代器做类似于切片操作
itertools.cycle(iterable):无限迭代操作之一,将传入的迭代对象无限迭代
itertools.chain(iterable1,iterable2):将两个可迭代对象连接合并
国际跳棋棋盘子类实现
class CheckersBoard(AbstractBoard):
def __init__(self):
self.populate_board()
def populate_board(self):
def black():
return create_piece(DRAUGHT,BLANK)
def white():
return create_piece(DRAUGHT,WHITE)
rows = (
# 4 black rows
(None, black()), (black(), None),
(None, black()),(black(), None),
# 2 blank rows
(None, None), (None, None),
# 4 white rows
(None, white()), (white(), None),
(None, white()), (white(), None)
)
#根据模板初始化棋盘列表
self.board = [list(itertools.islice(
itertools.cycle(squares), 0, len(rows))) for squares in rows]
国际象棋棋盘类实现
class ChessBoard(AbstractBoard):
def __init__(self):
super.__init()__(8,8)
#按照模板创建国际象棋棋盘
def populate_board(self):
for row, column in ((0, BLANK),(7, WHITE)):
for columns ,kind in (((0, 7), ROOK), ((1, 6), KNIGHT), ((2, 5), BISHOP), ((3,), QUEEN), ((4,), KING)):
for column in columns:
self.board[row][column] = create_piece(kind, color)
for column in range(8):
for row, color in ((1, BLACK), (6, WHITE)):
self.board[row][column] = create_piece(PAWN, color)
棋子创建函数
def create_piece(kind, color):
color = "White" if color == WHITE else "Black"
name = {DRAUGHT: "Draught", PAWN: "ChessPawn", ROOK: "ChessRook",
KNIGHT: "ChessKnight", BISHOP: "ChessBishop",
KING: "ChessKing", QUEEN: "ChessQueen"}[kind]
#这里使用动态创建实例的优雅(装逼)方式
return globals()[color + name]()
知识点补充 用内置函数type来创建类
Class = type(类型名称,含有基类名称的数组,含有类属性的字典)
globals()[类型名称] = Class
__slots__的用法,如果定义了slots,那么创建的实例中就不出现私有的dict,__slots__ = () 保证了实例中不会有任何数据
http://blog.csdn.net/tianqio/article/details/2374086
棋子父类
class Piece(str):
__slots__ = ()
动态创建各种棋子类
for code in itertools.chain((0x26C0,0x26c2),range(0x2654, 0x2660)):
char = chr(code)
name = unicodedata.name(char).title().replace(" ", "")
if name.endswith("sMan"):
name = name[:-4]
# 先写lambda表达式,然后用char填充外围lambda,创建new()函数(相当于是创建并调用外围lambda,创建了new()函数
new = (lambda char:lambda Class: Piece.__new__(Class, char))(char)
# 所有的lambda函数都叫lambda,于是起个名字
new.__name__ = "__new__"
#创建类
Class = type(name, (Piece,), dict(__slots=()), __new__=new)
globals()[name] = Class
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。