Python设计模式(十八)【组合模式】
2016-08-30 15:44
302 查看
天空黑暗到一定程度,星辰就会熠熠生辉。
"""组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。""" """ 一个类定义的组合对象,它可以用名称来存储分层使用的字典。 这个类是相同的分层字典,但它按名称提供方法来添加/访问/修改子元素,就像一个组合。 """ def normalize(val): """ 正常化一个特殊字符的字符串,以便它可以被用来作为一个Python对象一个属性 """ if val.find('-') != -1: val = val.replace('-', '_') return val def denormalize(val): """ 非规范化一个字符串""" if val.find('_') != -1: val = val.replace('_', '-') return val class SpecialDict(dict): """ 字典类,允许其键直接访问属性 """ def __getattr__(self, name): if name in self.__dict__: return self.__dict__[name] elif name in self: return self.get(name) else: # 检查非规范化的名字 name = denormalize(name) if name in self: return self.get(name) else: raise AttributeError('没有属性名称 %s' % name) def __setattr__(self, name, value): if name in self.__dict__: self.__dict__[name] = value elif name in self: self[name] = value else: # 检查非规范化的名字 name2 = denormalize(name) if name2 in self: self[name2] = value else: # 新属性 self[name] = value class CompositeDict(SpecialDict): """一类像一个层次词典。 这个类是基于组合设计模式""" ID = 0 def __init__(self, name=''): if name: self._name = name else: self._name = ''.join(('id#', str(self.__class__.ID))) self.__class__.ID += 1 self._children = [] # 链接到父亲 self._father = None self[self._name] = SpecialDict() def __getattr__(self, name): if name in self.__dict__: return self.__dict__[name] elif name in self: return self.get(name) else: # 检查非规范化的名字 name = denormalize(name) if name in self: return self.get(name) else: #查看孩子列表 child = self.findChild(name) if child: return child else: attr = getattr(self[self._name], name) if attr: return attr raise AttributeError('no attribute named %s' % name) def isRoot(self): """ Return 我是否根组件""" # 如果我没有父母,我的根节点 return not self._father def isLeaf(self): """ Return 叶节点 """ # 我是一片叶节点,如果我没有孩子 return not self._children def getName(self): """ 返回ConfigInfo对象的名称 """ return self._name def getIndex(self, child): """返回孩子ConfigInfo对象的'child'的索引""" if child in self._children: return self._children.index(child) else: return -1 def getDict(self): """ 返回包含的词典""" return self[self._name] def getProperty(self, child, key): """ 返回属性值""" # 首先get孩子的字典 childDict = self.getInfoDict(child) if childDict: return childDict.get(key, None) def setProperty(self, child, key, value): """ 设置属性的“key”的值 """ #首先get孩子的字典 childDict = self.getInfoDict(child) if childDict: childDict[key] = value def getChildren(self): """ 返回此对象的直接子列表 """ return self._children def getAllChildren(self): """ 返回此对象的所有子列表 """ l = [] for child in self._children: l.append(child) l.extend(child.getAllChildren()) return l def getChild(self, name): """ 用给定名称返回直接子对象 """ for child in self._children: if child.getName() == name: return child def findChild(self, name): """ 从树返回(用给定的名称)子对象 """ # 这将返回给定名称的第一个子对象 #任何其他具有类似名称的子对象不被考虑 for child in self.getAllChildren(): if child.getName() == name: return child def findChildren(self, name): """ 从树返回给定名称的子对象列表""" #这将返回给定名称的所有子项的列表,不论查询的深度 children = [] for child in self.getAllChildren(): if child.getName() == name: children.append(child) return children def getPropertyDict(self): """ 返回属性字典""" d = self.getChild('__properties') if d: return d.getDict() else: return {} def getParent(self): return self._father def __setChildDict(self, child): """ 私有方法来设置子对象的'child'的字典在内部字典 """ d = self[self._name] d[child.getName()] = child.getDict() def setParent(self, father): self._father = father def setName(self, name): """ 设置此ConfigInfo对象的名称为'name' """ self._name = name def setDict(self, d): self[self._name] = d.copy() def setAttribute(self, name, value): self[self._name][name] = value def getAttribute(self, name): return self[self._name][name] def addChild(self, name, force=False): """ 添加一个新的子节点 如果可选标志“force”设置为True,子对象被覆盖,如果它已经存在。 该函数返回子对象,无论是新的或现有的 """ if type(name) != str: raise ValueError('Argument should be a string!') child = self.getChild(name) if child: # print('Child %s present!' % name) # 如果force==True 更换它 if force: index = self.getIndex(child) if index != -1: child = self.__class__(name) self._children[index] = child child.setParent(self) self.__setChildDict(child) return child else: child = self.__class__(name) child.setParent(self) self._children.append(child) self.__setChildDict(child) return child def addChild2(self, child): """ 添加子对象'child'。如果它已经存在,它由缺省覆盖 """ currChild = self.getChild(child.getName()) if currChild: index = self.getIndex(currChild) if index != -1: self._children[index] = child child.setParent(self) # 未设置现有的子节点的父级 currChild.setParent(None) del currChild self.__setChildDict(child) else: child.setParent(self) self._children.append(child) self.__setChildDict(child) if __name__ == "__main__": window = CompositeDict('Window') frame = window.addChild('Frame') tfield = frame.addChild('Text Field') tfield.setAttribute('size', '20') btn = frame.addChild('Button1') btn.setAttribute('label', '提交') btn = frame.addChild('Button2') btn.setAttribute('label', '浏览') #print(window) #print(window.Frame) #print(window.Frame.Button1) #print(window.Frame.Button2) print(window.Frame.Button1.label) print(window.Frame.Button2.label)
运行结果如图:
相关文章推荐
- PYTHON以及插件安装
- 升级python以及安装anaconda
- Python模块之shelve
- Python设计模式(十七)【观察者模式】
- python logging模块学习
- Python:如何将字符串作为变量名
- Python的traceback
- Python模块之pickle
- python获取当前路径
- Python文件的操作2
- python 入门
- day11_python多线程实例代码——02
- python爬虫(一)
- day011_python多进程代码_01
- 【python】多进程学习
- python 进程间通信(下)
- 哈工大语言云(LTP)本地安装使用及Python调用
- Python爬虫利器二之Beautiful Soup的用法
- Python添加默认模块搜索路径
- Python设计模式(十六)【迭代器模式】