HeadFirst 设计模式--迭代器与组合模式
迭代器模式
迭代器模式提供一个方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
使用迭代器模式的好处:
让我们可以游走于聚合内部的每一个元素,而又不暴露其内部的表示
把游走的任务放在迭代器上,而不是聚合上,简化了聚合的接口和实现,也让责任各得其所。
tip:
虽然for循环可以直接遍历聚合对象,但是为了演示迭代器模式,在代码中,我们使用while循环。
class MenuItem:
name = None
desc = None
vegetarian = None
price = None
def __init__(self, name, desc, vegetarian, price):
self.name = name
self.desc = desc
self.vegetarian = vegetarian
self.price = price
from abc import ABC, abstractmethod
class Iterator(ABC):
@abstractmethod
def has_next(self):
pass
@abstractmethod
def next(self):
pass
class Menu(ABC):
@abstractmethod
def create_iterator(self):
pass
class DinerMenuIterator(Iterator):
menus = None
position = 0
def __init__(self, menus):
self.menus = menus
def next(self):
res = self.menus[self.position]
self.position += 1
return res
def has_next(self):
if self.position >= len(self.menus):
return False
else:
return True
class DinerMenu(Menu):
menus = []
def add_menu_item(self, item):
self.menus.append(item)
def create_iterator(self):
return DinerMenuIterator(self.menus)
class Waitress:
menu = None
def __init__(self, menus):
self.menus = menus
def print_menus(self):
menu_iter = self.menus.create_iterator
self.print_menus_func(menu_iter)
def print_menus_func(self, iterator):
while iterator.has_next():
print(iterator.next())
在代码中,Waitress通过使用菜单的迭代器,来实现了菜单的遍历。
组合模式
组合模式允许将对象组合成树形结构来表现“整体/部分”的层次结构。组合可以让客户以一致的方式处理个别对象及对象组合。
组合模式的好处:
允许客户对个别对象以及组合对象一视同仁
组合结构内的任意对象成为组件,组件可以是组件也可以是叶节点
from abc import ABC, abstractmethod
class MenuComponent(ABC):
def add(self, menu_component):
raise NotImplementedError
def remove(self, menu_component):
raise NotImplementedError
def get_child(self, i):
raise NotImplementedError
def get_name(self):
raise NotImplementedError
def get_description(self):
raise NotImplementedError
def get_price(self):
raise NotImplementedError
def is_vegetarian(self):
raise NotImplementedError
def print(self):
raise NotImplementedError
class MenuItem(MenuComponent):
name = None
description = None
vegetarian = None
price = None
def __init__(self, name, description, vegetarian, price):
self.name = name
self.description = description
self.vegetarian = vegetarian
self.price = price
def get_name(self):
return self.name
def get_description(self):
return self.description
def get_price(self):
return self.price
def is_vegetarian(self):
return self.vegetarian
def print(self):
msg = f" {self.get_name()}{'(v)' if self.is_vegetarian() else ''},{self.get_price()} --{self.get_description()}"
print(msg)
class Menu(MenuComponent):
menuComponents = []
name = None
description = None
def __init__(self, name, description):
self.name = name
self.description = description
def add(self, menu_item):
self.menuComponents.append(menu_item)
def remove(self, menu_item):
self.menuComponents.remove(menu_item)
def get_child(self, i):
return self.menuComponents[i]
def get_name(self):
return self.name
def get_description(self):
return self.description
def print(self):
print(f'''\n {self.get_name()}
{self.get_description()}
------------------------
''')
# 书中使用的是has_next()与while配合,但Python的迭代器中没有has_next()
# 所以此处使用while循环
for i in self.menuComponents:
i.print()
class Waitress:
all_menus = None
def __init__(self, all_menus):
self.all_menus = all_menus
def print_menus(self):
print(self.all_menus)
在此处代码中,菜单和菜单项有相同的父类,同时将迭代及输出的任务放到了菜单中。
组合迭代器
使用组合迭代器,可以使用统一的方法处理组合模式中的组件(叶子和节点)。
from abc import ABC, abstractmethod
class MenuComponent(ABC):
def add(self, menu_component):
raise NotImplementedError
def remove(self, menu_component):
raise NotImplementedError
def get_child(self, i):
raise NotImplementedError
def get_name(self):
raise NotImplementedError
def get_description(self):
raise NotImplementedError
def get_price(self):
raise NotImplementedError
def is_vegetarian(self):
raise NotImplementedError
def print_(self):
raise NotImplementedError
def create_iterator(self):
raise Exception
class Iterator(ABC):
@abstractmethod
def has_next(self):
pass
@abstractmethod
def next(self):
pass
class NullIterator(Iterator):
def next(self):
return None
def has_next(self):
return False
class CompositeIterator(Iterator):
stack = []
def __init__(self, iterator):
self.stack.append(iterator)
def next(self):
if not self.has_next():
return None
iterator = self.stack[-1]
component = iterator.next()
if isinstance(component, Menu):
self.stack.append(component.create_iterator())
return component
def has_next(self):
# 检查堆栈是否被清空
if not self.stack:
return False
# 递归检查下一个元素是否有值
iterator = self.stack[-1]
if not iterator.has_next():
# 当下一个元素为空时,将其弹出
self.stack.pop()
else:
return True
class MenuItem(MenuComponent):
name = None
description = None
vegetarian = None
price = None
def __init__(self, name, description, vegetarian, price):
self.name = name
self.description = description
self.vegetarian = vegetarian
self.price = price
def get_name(self):
return self.name
def get_description(self):
return self.description
def get_price(self):
return self.price
def is_vegetarian(self):
return self.vegetarian
def print_(self):
msg = f" {self.get_name()}{'(v)' if self.is_vegetarian() else ''},{self.get_price()} --{self.get_description()}"
print(msg)
def create_iterator(self):
return NullIterator()
class Menu(MenuComponent):
menuComponents = []
name = None
description = None
def __init__(self, name, description):
self.name = name
self.description = description
def add(self, menu_item):
self.menuComponents.append(menu_item)
def remove(self, menu_item):
self.menuComponents.remove(menu_item)
def get_child(self, i):
return self.menuComponents[i]
def get_name(self):
return self.name
def get_description(self):
return self.description
def print_(self):
print(f'''\n {self.get_name()}
{self.get_description()}
------------------------
''')
# 书中使用的是has_next()与while配合,但Python的迭代器中没有has_next()
# 所以此处使用while循环
for i in self.menuComponents:
i.print()
def create_iterator(self):
return CompositeIterator(self.menuComponents.__iter__())
class Waitress:
all_menus = None
def __init__(self, all_menus):
self.all_menus = all_menus
def print_menus(self):
self.all_menus.print_()
def print_vegetarian_menu(self):
iterator = self.all_menus.create_iterator()
print("\nVEGETARIAN MENU\n----")
while (iterator.has_next()):
menu_component = iterator.next()
try:
if menu_component.is_vegetarian():
menu_component.print_()
except Exception as e:
...
License:
CC BY 4.0