您的位置:首页 > 编程语言 > Python开发

python创建型设计模式学习——工厂方法模式

2017-01-04 12:06 525 查看

应用情形

如果子类的某个方法要根据情况,来决定用什么类去实例化相关对象,可以考虑工厂方法模式。此模式可以单独使用,也可以再无法预知对象类型的时候使用,例如待初始化的对象类型要从文件中读入或者由用户输入。

参照书上例子,根据用户的调用,创建国际跳棋或者国际象棋的棋盘。



引入相关模块

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python 设计模式 应用