下面我们来看下工厂模式案例
首先我们看pygame实现的一个案例:
按下s键或c键切换显示圆形与方形,按上下左右键移动图形,调用者main_01直接操作类实现的
import pygame
class Shape:
def __init__(self,x,y,screen):
self.screen=screen
self.x=x
self.y=y
def draw(self):
raise NotImplementedError()
def move(self,direction):
if direction=='up':
self.y-=4
elif direction=='down':
self.y+=4
elif direction=='left':
self.x-=4
elif direction=='right':
self.x+=4
class Square(Shape):
def draw(self):
pygame.draw.rect(
self.screen,
(255,255,0),
pygame.Rect(self.x,self.y,20,20)
)
class Circle(Shape):
def draw(self):
pygame.draw.circle(
self.screen,
(0,255,255),
(self.x,self.y),
10
)
def main_01():
window_dimesions=800,600
screen=pygame.display.set_mode(window_dimesions)
obj=Square(100,100,screen)
play_quits=False
while not play_quits:
for event in pygame.event.get():
if event.type==pygame.QUIT:
play_quits=True
pressed=pygame.key.get_pressed()
if pressed[pygame.K_UP]:
obj.move('up')
elif pressed[pygame.K_DOWN]:
obj.move('down')
elif pressed[pygame.K_LEFT]:
obj.move('left')
elif pressed[pygame.K_RIGHT]:
obj.move('right')
elif pressed[pygame.K_c]:
obj=Circle(100,100,screen)
elif pressed[pygame.K_s]:
obj=Square(100,100,screen)
screen.fill((0,0,0))
obj.draw()
pygame.display.flip()
if __name__=="__main__":
main_01()
下面我们改写一下这个案例,利用工厂方法。
将具体图形类的创建交给工厂方法,我们主逻main_01只需要调用工厂方法来获取图形类的实例,这样万一以后图形类升级后创建图形类变复杂了也不会让图形类使用者感到困难。
更重要的是这样的好处是将图形类与主逻辑main_01解耦合,通过工厂来对类创建,管理和控制,往后图形的的增加或者升级我们只需要修改工厂方法的内部实现,无需过多修改main_01的代码
import pygame
class Shape:
def __init__(self,x,y,screen):
self.x=x
self.y=y
self.screen=screen
def draw(self):
raise NotImplementedError()
def move(self,direction):
if direction=='up':
self.y-=4
elif direction=='down':
self.y+=4
elif direction=='left':
self.x-=4
elif direction=='right':
self.x+=4
@staticmethod
def factory(type,screen):
if type=='circle':
return Circle(100,100,screen)
elif type=='square':
return Square(100,100,screen)
class Square(Shape):
def draw(self):
pygame.draw.rect(
self.screen,
(255,255,0),
pygame.Rect(self.x,self.y,20,20)
)
class Circle(Shape):
def draw(self):
pygame.draw.circle(
self.screen,
(0,255,255),
(self.x,self.y),
10
)
def main_01():
window_dimesionts=800,600
screen=pygame.display.set_mode(window_dimesionts)
obj=Shape.factory('square',screen)
player_quits=False
while not player_quits:
for event in pygame.event.get():
if event.type==pygame.QUIT:
player_quits=True
pressed=pygame.key.get_pressed()
if pressed[pygame.K_UP]:
obj.move('up')
elif pressed[pygame.K_DOWN]:
obj.move('down')
elif pressed[pygame.K_LEFT]:
obj.move('left')
elif pressed[pygame.K_RIGHT]:
obj.move('right')
elif pressed[pygame.K_c]:
# obj=Circle(100,100,screen)
obj=Shape.factory('circle',screen)
elif pressed[pygame.K_s]:
# obj=Square(100,100,screen)
obj=Square.factory('square',screen)
screen.fill((0,0,0))
obj.draw()
pygame.display.flip()
if __name__=="__main__":
main_01()
下面再看另一个案例,利用抽象工厂,利用抽象工厂的抽象方法来规范工厂的接口
'''
抽象工厂模式
根据用户输入age的不同,创建不同的工厂,然后通过工厂创建处理具体对象用来处理事件
'''
import abc
#先抽象出对象接口,让创建出来的对象符合标准
class Hero_Abstract(metaclass=abc.ABCMeta):
@abc.abstractmethod
def interact_with(self,obstacle):
pass
class Obstacle_Abstract(metaclass=abc.ABCMeta):
@abc.abstractmethod
def action(self):
pass
#再抽象出工厂的借口,让工厂能符合协议的方式生成对象
class World_Base(metaclass=abc.ABCMeta):
@abc.abstractmethod
def make_character(self):
pass
@abc.abstractmethod
def make_obstacle(self):
pass
#-------------------青蛙游戏,专供0~11岁儿童
#青蛙是Hero单位
class Forg(Hero_Abstract):
def __init__(self,name):
self.name=name
def __str__(self):
return self.name
def interact_with(self,obstacle):
print("{} th the frog encounters {} and {}!".format(self,obstacle,obstacle.action()))
#Bug是obstacle单位
class Bug(Obstacle_Abstract):
def __str__(self):
return 'a bug'
def action(self):
return 'eats it'
#FrogWorld是World单位
class FrogWorld(World_Base):
def __init__(self,name):
print(self)
self.player_name=name
def __str__(self):
return "\n\n\t------ Frog World ------"
def make_character(self):
return Forg(self.player_name)
def make_obstacle(self):
return Bug()
#-------------------巫师游戏,专供11岁往上儿童
#wizard是hero单位
class Wizard(Hero_Abstract):
def __init__(self,name):
self.name=name
def __str__(self):
return self.name
def interact_with(self,obstacle):
print("{} the Wizard batteles against {} and {}!".format(self,obstacle,obstacle.action()))
#ork是obstacle单位
class Ork(Obstacle_Abstract):
def __str__(self):
return 'an evial ork'
def action(self):
return 'kills it'
#Wizard是WordBase单位
class WizardWorld(World_Base):
def __init__(self,name):
print(self)
self.player_name=name
def __str__(self):
return '\n\n\t------ Wizard World ------'
def make_character(self):
return Wizard(self.player_name)
def make_obstacle(self):
return Ork()
#游戏入口
class GameEnvironment:
def __init__(self,factory):
self.hero=factory.make_character()
self.obstacle=factory.make_obstacle()
def play(self):
self.hero.interact_with(self.obstacle)
def validate_age(name):
try:
age=input('Welcome {}. How old are you?:'.format(name))
age=int(age)
except Exception as e:
print("Age {} is valid, plz try again...Try again".format(age))
return (False,age)
return (True,age)
def main01():
name=input("Hello. what's your name?:")
valid_input=False
while not valid_input:
valid_input,age=validate_age(name)
game=FrogWorld if age<18 else WizardWorld
environment=GameEnvironment(game(name))
environment.play()
if __name__=="__main__":
main01()
我们再来看个例子,按下1,2,3,4,5,6沿着对角线从左上方向右下方显示特定图案
#demo03的升级版,采用抽闲方法构成抽象工厂规范代码
import pygame
import abc
#抽象工厂
class Factory_Abstractory(metaclass=abc.ABCMeta):
@abc.abstractmethod
def make_object(self,x,y,object_class_name):
pass
#图形对象基类
class Base_Object(metaclass=abc.ABCMeta):
def __init__(self,x,y):
self.x=x
self.y=y
def move(self,direction):
if direction=='up':
self.y-=4
elif direction=='down':
self.y+=4
elif direction=='left':
self.x-=4
elif direction=='right':
self.x+=4
#绘制图形
@abc.abstractmethod
def draw(self,screen):
pass
#小圆
class Circle_Small(Base_Object):
def draw(self,screen):
screen.fill((0,0,0))
pygame.draw.circle(
screen,
(0, 255, 255),
(self.x, self.y),
8
)
#园
class Circle(Base_Object):
def draw(self,screen):
screen.fill((0,0,0))
pygame.draw.circle(
screen,
(0, 255, 255),
(self.x, self.y),
15
)
#大圆
class Circle_Big(Base_Object):
def draw(self,screen):
screen.fill((0,0,0))
pygame.draw.circle(
screen,
(0, 255, 255),
(self.x, self.y),
25
)
#正方形
class Square(Base_Object):
def draw(self,screen):
screen.fill((0,0,0))
pygame.draw.rect(
screen,
(255,255,0),
pygame.Rect(self.x,self.y,20,20)
)
#长方形(x向长度大于y向长度)
class Square_Low(Base_Object):
def draw(self,screen):
screen.fill((0,0,0))
pygame.draw.rect(
screen,
(255,255,0),
pygame.Rect(self.x,self.y,50,20)
)
#长方形(x向长度小于y向长度)
class Square_High(Base_Object):
def draw(self,screen):
screen.fill((0,0,0))
pygame.draw.rect(
screen,
(255,255,0),
pygame.Rect(self.x,self.y,20,50)
)
#方形工厂与圆形工厂
class Square_Factory(Factory_Abstractory):
def make_object(self,x,y,object_class_name):
if object_class_name=='s':
return Square(x,y)
elif object_class_name=='sl':
return Square_Low(x,y)
elif object_class_name=='sh':
return Square_High(x,y)
class Circle_Factory(Factory_Abstractory):
def make_object(self,x,y,object_class_name):
if object_class_name=='c':
return Circle(x,y)
elif object_class_name=='cs':
return Circle_Small(x,y)
elif object_class_name=='cb':
return Circle_Big(x,y)
def draw_object_function(factory,x,y,object_name,screen):
obj=factory.make_object(x,y,object_name)
obj.draw(screen)
def main_01():
window_dimesions=900,900
screen=pygame.display.set_mode(window_dimesions)
sq_factory=Square_Factory()
ci_factory=Circle_Factory()
play_quits=False
while not play_quits:
for event in pygame.event.get():
if event.type==pygame.QUIT:
play_quits=True
pressed=pygame.key.get_pressed()
if pressed[pygame.K_1]:
draw_object_function(sq_factory,100,100,'s',screen)
elif pressed[pygame.K_2]:
draw_object_function(sq_factory,150,150,'sl',screen)
elif pressed[pygame.K_3]:
draw_object_function(sq_factory,200,200,'sh',screen)
elif pressed[pygame.K_4]:
draw_object_function(ci_factory,250,250,'c',screen)
elif pressed[pygame.K_5]:
draw_object_function(ci_factory,300,300,'cs',screen)
elif pressed[pygame.K_6]:
draw_object_function(ci_factory,350,350,'cb',screen)
pygame.display.flip()
if __name__=='__main__':
main_01()
网友评论