Posts 设计模式-组合模式
Post
Cancel

设计模式-组合模式

概念解析

组合模式,指的是:将对象组合成树形结构以表示“整体-部分”的层次结构,组合使得用户对单个对象和复合对象的使用具备一致性。其设计要点为:

  • 理清部分与整体的关系,了解对象的组成结构
  • 组合模式为一种具有层次关系的树形结构,不能再分的叶子节点为具体的组件,即最小的逻辑单元;具有子节点(由多个子组件组成)被称为复合组件,即组合对象;对于复合组件和子组件两者,用户对两者的使用具备一致性。

组合模式的类图如下:

img

组合模式的优点在于:

  • 调用简单,组合对象可以像一般对象一样使用
  • 组合对象可以自由地增加、删除组件,可灵活地组合不同对象

缺点在于:

  • 层次结构太深的话,组合结构会变得很复杂

组合模式适用的场景:

  • 对象之间具备明显的”部分-整体”的关系,或者层次关系
  • 组合对象和单一对象具有相同或类似行为(方法),用户希望统一地使用组合结构中的所有对象

设计模板

子组件和复合组件的代码模板如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from abc import ABCMeta, abstractmethod


class Component(metaclass=ABCMeta):
    """子组件"""

    def __init__(self, name):
        self._name = name

    def get_name(self):
        return self._name

    def is_composite(self):
        return False

    @abstractmethod
    def feature(self, indent):
        # indent仅用于内容输出时的缩进
        pass


class Composite(Component):
    """复合组件"""

    def __init__(self, name):
        super().__init__(name)
        self._components = []

    def add_component(self, component):
        self._components.append(component)

    def remove_component(self, component):
        self._components.remove(component)

    def is_composite(self):
        return True

    def feature(self, indent):
        indent += "\t"
        for component in self._components:
            print(indent, end="")
            component.feature(indent)

实例分析

场景说明:对文件/文件夹进行遍历操作,文件和文件夹两者便存在明显的层次关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import os

class FileDetail(Component):
    """文件详情"""
    def __init__(self, name):
        super().__init__(name)
        self._size = 0

    def set_size(self, size):
        self._size = size

    def get_file_size(self):
        return self._size

    def feature(self, indent):
        # 文件大小,单位:KB,精确度:2位小数
        file_size = round(self._size / float(1024), 2)
        print("文件名称: %s,文件大小:%s KB" % (self._name, file_size))


class FolderDetail(Composite):
    """文件夹详情"""
    def __init__(self, name):
        super().__init__(name)
        self._count = 0

    def set_count(self):
        return self._count

    def feature(self, indent):
        print("文件名: %s,文件数量:%d。包含的文件:" % (self._name, self._count))
        super().feature(indent)


def scan_dir(root_path, folder_detail):
    """扫描某一文件夹下的所有目录"""
    if not os.path.isdir(root_path):
        raise ValueError("root_path不是有效路径:%s" % root_path)

    if filder_detail is None:
        raise ValueError("folder_detail不能为空!")

    file_names = os.listdir(root_path)
    for file_name in file_names:
        file_path = os.path.join(root_path, file_name)
        if os.path.isdir(file_path):
            folder = FolderDetails(file_name)
            scan_dir(file_path, folder)
            folder_detail.add_component(folder)
        else:
            file_detail = FileDetail(file_name)
            file_detail.setSize(os.path.get_size(file_path))
            folder_detail.add_componet(file_detail)
            folder_detail.set_count(folder_detail.get_count() + 1)


def test_dir():
    folder = FolderDetail("测试目录")
    scan_dir("./test", folder)
    folder.feature("")
This post is licensed under CC BY 4.0 by the author.

设计模式-构建模式

设计模式-迭代模式