Python设计模式——组合模式

组合模式(Composite Pattern)可用来统合类体系中的这两种对象,一种对象能够包含体系中的其他对象,另一种为基本的单元对象,并不能包含其他对象。

(Python中其实很少使用到组合模式,因为采用dict就可以实现相同的功能)

常规方法,我们先可以用两种基类来分别表示这两种类型的组件。

先让我们看看运行的结果:

$0.40 Pencil
$1.60 Ruler
$0.20 Eraser
$2.20 Pencil Set
      $0.40 Pencil
      $1.60 Ruler
      $0.20 Eraser
$3.60 Boxed Pencil Set
      $1.00 Box
      $2.20 Pencil Set
            $0.40 Pencil
            $1.60 Ruler
            $0.20 Eraser
      $0.40 Pencil

其中main()函数中:

def main():
    pencil = SimpleItem("Pencil", 0.40)
    ruler = SimpleItem("Ruler", 1.60)
    eraser = SimpleItem("Eraser", 0.20)
    pencilSet = CompositeItem("Pencil Set", pencil, ruler, eraser)
    box = SimpleItem("Box", 1.00)
    boxedPencilSet = CompositeItem("Boxed Pencil Set", box, pencilSet)
    boxedPencilSet.add(pencil)
    for item in (pencil, ruler, eraser, pencilSet, boxedPencilSet):
        item.print()

层次结构如图所示
由组合体元素与非组合体元素所构成的层次结构

其UML:
uml

AbstractItem要求所有子类的对象明确是不是组合体,同时还要求子类对象必须可迭代。

class AbstractItem(object):
    __metaclass__=abc.ABCMeta

    @abc.abstractproperty
    def composite(self):
        pass


    def __iter__(self):
        return iter([])

SimpleItem类用来表示组合单元,也就是非组合体

class SimpleItem(AbstractItem):

    def __init__(self, name, price=0.00):
        self.name = name
        self.price = price


    @property
    def composite(self):
        """
            表明是非组合体
        """
        return False


    def print(self, indent="", file=sys.stdout):
        print("{}${:.2f} {}".format(indent, self.price, self.name),
                file=file)

AbstractCompositeItem作为CompositeItem的基类,它实现了组合体所需的添加,移除,迭代等功能

class AbstractCompositeItem(AbstractItem):

    def __init__(self, *items):
        self.children = []
        if items:
            self.add(*items)


    def add(self, first, *items):
        self.children.append(first)
        if items:
            self.children.extend(items)


    def remove(self, item):
        self.children.remove(item)


    def __iter__(self):
        return iter(self.children)

接下来就是组合体CompositeItem的具体实现:

class CompositeItem(AbstractCompositeItem):

    def __init__(self, name, *items):
        super().__init__(*items)
        self.name = name


    @property
    def composite(self):
        """
            确认是组合体
        """
        return True


    @property
    def price(self):
        return sum(item.price for item in self)


    def print(self, indent="", file=sys.stdout):
        print("{}${:.2f} {}".format(indent, self.price, self.name),
                file=file)
        for child in self:
            child.print(indent + "      ")

这样就实现分别用两个类来表示组合体与非组合体了。但是这种方法导致我们创建了两个抽象类,两个具体类,接口也没有完全统一,如果我们再能忍受少许的额外开销也许将会更简单。

接下来我们使用一个类来表示组合体与非组合体,这二者接口完全一直,只是非组合体并不能使用某些接口
它的main函数

def main():
    pencil = Item.create("Pencil", 0.40)
    ruler = Item.create("Ruler", 1.60)
    eraser = make_item("Eraser", 0.20)
    pencilSet = Item.compose("Pencil Set", pencil, ruler, eraser)
    box = Item.create("Box", 1.00)
    boxedPencilSet = make_composite("Boxed Pencil Set", box, pencilSet)
    boxedPencilSet.add(pencil)
    for item in (pencil, ruler, eraser, pencilSet, boxedPencilSet):
        item.print()
    assert not pencil.composite
    pencil.add(eraser, box)
    assert pencil.composite
    pencil.print()
    pencil.remove(eraser)
    assert pencil.composite
    pencil.remove(box)
    assert not pencil.composite
    pencil.print()

类的代码

class Item:

    def __init__(self, name, *items, price=0.00):
        """
            将items加入children
            可以依据children判断是否是组合体
        """
        self.name = name
        self.price = price
        self.children = []
        if items:
            self.add(*items)

这里定义了两个工厂方法(还记得之前的工厂模式吗?),其中create创建非组合体,compose创建组合体


    @classmethod
    def create(Class, name, price):
        return Class(name, price=price)


    @classmethod
    def compose(Class, name, *items):
        return Class(name, *items)

我们还可以在类外面创建这两个工厂方法来创建非组合体和组合体

def make_item(name, price):
    return Item(name, price=price)


def make_composite(name, *items):
    return Item(name, *items)

composite判断是否是组合体


    @property
    def composite(self):
        return bool(self.children)

定义组合体方法

    def add(self, first, *items):
        self.children.extend(itertools.chain((first,), items))


    def remove(self, item):
        self.children.remove(item)


    def __iter__(self):
        return iter(self.children)

打印

    @property
    def price(self):
        return (sum(item.price for item in self) if self.children else
                self.__price)


    @price.setter
    def price(self, price):
        self.__price = price


    def print(self, indent="", file=sys.stdout):
        print("{}${:.2f} {}".format(indent, self.price, self.name),
                file=file)
        for child in self:
            child.print(indent + "      ")
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值