Python设计模式(十八)【组合模式】

天空黑暗到一定程度,星辰就会熠熠生辉。

"""组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。"""

""" 一个类定义的组合对象,它可以用名称来存储分层使用的字典。 这个类是相同的分层字典,但它按名称提供方法来添加/访问/修改子元素,就像一个组合。 """

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设计模式(十八)【组合模式】》

    原文作者:风灵使
    原文地址: https://blog.csdn.net/wulex/article/details/52369918
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞