下面我們來看下工廠模式案例
首先我們看pygame實現(xiàn)的一個案例:
按下s鍵或c鍵切換顯示圓形與方形,按上下左右鍵移動圖形斗忌,調(diào)用者main_01直接操作類實現(xiàn)的
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()
下面我們改寫一下這個案例闯第,利用工廠方法逢渔。
將具體圖形類的創(chuàng)建交給工廠方法,我們主邏main_01只需要調(diào)用工廠方法來獲取圖形類的實例乡括,這樣萬一以后圖形類升級后創(chuàng)建圖形類變復雜了也不會讓圖形類使用者感到困難肃廓。
更重要的是這樣的好處是將圖形類與主邏輯main_01解耦合智厌,通過工廠來對類創(chuàng)建,管理和控制盲赊,往后圖形的的增加或者升級我們只需要修改工廠方法的內(nèi)部實現(xiàn)铣鹏,無需過多修改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()
下面再看另一個案例,利用抽象工廠哀蘑,利用抽象工廠的抽象方法來規(guī)范工廠的接口
'''
抽象工廠模式
根據(jù)用戶輸入age的不同诚卸,創(chuàng)建不同的工廠,然后通過工廠創(chuàng)建處理具體對象用來處理事件
'''
import abc
#先抽象出對象接口绘迁,讓創(chuàng)建出來的對象符合標準
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
#再抽象出工廠的借口合溺,讓工廠能符合協(xié)議的方式生成對象
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的升級版,采用抽閑方法構(gòu)成抽象工廠規(guī)范代碼
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()