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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huxiaotong_exp/article/details/54016055

应用情形

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

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

棋盘游戏

引入相关模块

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

猜你喜欢

转载自blog.csdn.net/huxiaotong_exp/article/details/54016055