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)

运行结果如图:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值