首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >python: Composite Pattern

python: Composite Pattern

作者头像
geovindu
发布2026-06-18 17:01:37
发布2026-06-18 17:01:37
660
举报

珠宝行业的典型场景: 叶子节点:单颗钻石、单条项链、单个戒指(不可拆分) 容器节点:订婚套装(戒指 + 项链 + 耳环)、节日礼盒(多件珠宝组合)、珠宝柜台(多个套装 / 单品) 结合珠宝实体属性(材质、重量、单价、证书编号)和业务流程(计算总价、生成销售清单、库存盘点)

代码语言:javascript
复制
# encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:组合模式 Composite Pattern
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : PyCharm 2024.3.6 python 3.11
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/3/7 15:14
# User      :  geovindu
# Product   : PyCharm
# Project   : pydesginpattern
# File      : JewelryComponent.py
 
from abc import ABC, abstractmethod
 
 
# ===================== 1 珠宝基础抽象类(Component)=====================
 
class JewelryComponent(ABC):
    """
     统一叶子节点和容器节点的接口,定义珠宝核心属性和业务方法
    """
    def __init__(self, name: str, material: str, cert_num: str = ""):
        """
 
        :param name:
        :param material:
        :param cert_num:
        """
        self.name = name
        """
        珠宝名称(如:18K金钻戒、订婚套装)
        """
        self.material = material
        """
        材质(如:铂金、黄金、钻石)
        """
        self.cert_num = cert_num
        """
        证书编号(套装无单独证书,单品必填)
        """
 
 
    @abstractmethod
    def calculate_total_price(self) -> float:
        """
        业务方法1:计算总价(核心)
        :return:
        """
        pass
 
 
    @abstractmethod
    def generate_sales_list(self, indent: str = "") -> str:
        """
        业务方法2:生成销售清单
        :param indent:
        :return:
        """
        pass
 
 
    @abstractmethod
    def inventory_check(self) -> int:
        """
        业务方法3:库存盘点(统计数量)
        :return:
        """
        pass
代码语言:javascript
复制
# encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:组合模式 Composite  Pattern
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : PyCharm 2024.3.6 python 3.11
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/3/7 15:17
# User      :  geovindu
# Product   : PyCharm
# Project   : pydesginpattern
# File      : SingleJewelry.py
 
from CompositePattern.JewelryComponent import JewelryComponent
 
 
# =====================2 叶子节点:单个珠宝(Leaf)=====================
 
class SingleJewelry(JewelryComponent):
    """
    不可拆分的单个珠宝,包含核心实体属性(重量、单价)
    """
    def __init__(self, name: str, material: str, weight: float, unit_price: float, cert_num: str):
        """
 
        :param name:
        :param material:
        :param weight:
        :param unit_price:
        :param cert_num:
        """
        super().__init__(name, material, cert_num)
        """
        调用父类 (超类)的一个方法。 super () 是用来解决多重继承问题的
        """
        self.weight = weight
        """
        重量(如:钻石0.5克拉、黄金5克)
        """
        self.unit_price = unit_price
        """
        单价(如:钻石8000元/克拉、黄金500元/克)
        """
 
 
    def calculate_total_price(self) -> float:
        """
        单个珠宝总价 = 重量 × 单价
        :return:
        """
        return round(self.weight * self.unit_price, 2)
 
 
    def generate_sales_list(self, indent: str = "") -> str:
        """
         生成单品销售清单(包含实体属性)
        :param indent:
        :return:
        """
        return (
            f"{indent}[单品] {self.name}\n"
            f"{indent}  - 材质:{self.material}\n"
            f"{indent}  - 重量:{self.weight}(单位)\n"
            f"{indent}  - 单价:{self.unit_price}元/单位\n"
            f"{indent}  - 证书编号:{self.cert_num}\n"
            f"{indent}  - 小计:{self.calculate_total_price()}元"
        )
 
 
    def inventory_check(self) -> int:
        """
        单品库存数量为1
        :return:
        """
        return 1
代码语言:javascript
复制
# encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:组合模式 Composite  Pattern
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : PyCharm 2024.3.6 python 3.11
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/3/7 15:21
# User      :  geovindu
# Product   : PyCharm
# Project   : pydesginpattern
# File      : JewelryComposite.py
from CompositePattern.JewelryComponent import JewelryComponent
from typing import List
 
 
# ===================== 3 容器节点:珠宝组合(Composite)=====================
 
class JewelryComposite(JewelryComponent):
    """
    可包含多个单品/子组合,如套装、礼盒
    """
    def __init__(self, name: str, material: str = "组合装"):
        """
 
        :param name:
        :param material:
        """
        super().__init__(name, material)
        self.children: List[JewelryComponent] = []  # 子节点(单品/组合)
 
 
    def add(self, jewelry: JewelryComponent) -> None:
        """
         添加珠宝(单品/组合)
        :param jewelry:
        :return:
        """
        self.children.append(jewelry)
 
 
    def remove(self, jewelry: JewelryComponent) -> None:
        """
         移除珠宝
        :param jewelry:
        :return:
        """
        self.children.remove(jewelry)
 
 
    def calculate_total_price(self) -> float:
        """
         组合总价 = 所有子节点总价之和
        :return:
        """
        total = sum(child.calculate_total_price() for child in self.children)
        return round(total, 2)
 
 
    def generate_sales_list(self, indent: str = "") -> str:
        """
         生成组合销售清单(递归遍历子节点)
        :param indent:
        :return:
        """
        list_str = f"{indent}[组合] {self.name}\n{indent}  - 包含:\n"
        for child in self.children:
            list_str += child.generate_sales_list(indent + "    ") + "\n"
        list_str += f"{indent}  - 组合总价:{self.calculate_total_price()}元"
        return list_str
 
 
    def inventory_check(self) -> int:
        """
        组合库存数量 = 所有子节点数量之和
        :return:
        """
        return sum(child.inventory_check() for child in self.children)
代码语言:javascript
复制
# encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:组合模式 Composite  Pattern
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : PyCharm 2024.3.6 python 3.11
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/3/7 15:24
# User      :  geovindu
# Product   : PyCharm
# Project   : pydesginpattern
# File      : CompositeBll.py
from CompositePattern.SingleJewelry import SingleJewelry
from CompositePattern.JewelryComposite import JewelryComposite
 
 
# =====================4 客户端业务流程测试 =====================
class CompositeBll(object):
    """
    组合模式 Composite  Pattern
    """
    def demo(self):
        """
         组合模式 Composite  Pattern
        :return:
        """
        # 1. 创建单个珠宝(叶子节点)
        diamond_ring = SingleJewelry(
            name="18K金钻戒",
            material="18K金+钻石",
            weight=0.5,  # 钻石0.5克拉
            unit_price=8000,  # 钻石8000元/克拉
            cert_num="GIA20260307001"
        )
        gold_necklace = SingleJewelry(
            name="足金项链",
            material="足金",
            weight=5.2,  # 黄金5.2克
            unit_price=500,  # 黄金500元/克
            cert_num="NGTC20260307002"
        )
        pearl_earrings = SingleJewelry(
            name="珍珠耳环",
            material="925银+珍珠",
            weight=2.0,  # 珍珠2.0克
            unit_price=300,  # 珍珠300元/克
            cert_num="NGTC20260307003"
        )
 
        # 2. 创建珠宝组合(容器节点):订婚套装(戒指+项链+耳环)
        engagement_set = JewelryComposite(name="订婚珠宝套装")
        engagement_set.add(diamond_ring)
        engagement_set.add(gold_necklace)
        engagement_set.add(pearl_earrings)
 
        # 3. 创建更高层级组合:节日礼盒(订婚套装+额外手链)
        bracelet = SingleJewelry(
            name="铂金手链",
            material="铂金",
            weight=8.0,
            unit_price=450,
            cert_num="NGTC20260307004"
        )
        festival_gift = JewelryComposite(name="春节珠宝礼盒")
        festival_gift.add(engagement_set)
        festival_gift.add(bracelet)
 
        # ===================== 业务流程1:计算总价 =====================
        print("=== 业务流程1:计算总价 ===")
        print(f"单颗钻戒总价:{diamond_ring.calculate_total_price()}元")
        print(f"订婚套装总价:{engagement_set.calculate_total_price()}元")
        print(f"春节礼盒总价:{festival_gift.calculate_total_price()}元\n")
 
        # ===================== 业务流程2:生成销售清单 =====================
        print("=== 业务流程2:生成销售清单 ===")
        print(festival_gift.generate_sales_list())
        print()
 
        # ===================== 业务流程3:库存盘点 =====================
        print("=== 业务流程3:库存盘点 ===")
        print(f"订婚套装库存数量:{engagement_set.inventory_check()}件")
        print(f"春节礼盒库存数量:{festival_gift.inventory_check()}件")

调用:

代码语言:javascript
复制
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述: 设计模式 Design Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : PyCharm 2023.1 python 3.11
# OS        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  oracle 21c Neo4j
# Datetime  : 2026/2/18 20:58
# User      : geovindu
# Product   : PyCharm
# Project   : pydesginpattern
# File      : main.py
# explain   : 学习
 
import Controller.CheckPatterns
 
 
def select_design_pattern() -> tuple[int, Controller.CheckPatterns.DesignPattern | None]:
    """
    返回 (序列号, 选中的枚举对象),退出则返回 (0, None)
    :return:
    """
    print("\n=== 方式3:用户选择展示 ===")
    print("可选设计模式(输入0或q退出):")
    for idx, pattern in enumerate(Controller.CheckPatterns.DesignPattern, 1):
        print(f"{idx}. {pattern._name_to_cn(pattern.name)}({pattern.name})")
    print("0. 退出")
 
    while True:
        user_input = input("\n请输入序号选择要展示的设计模式(输入0/q退出):").strip()
        if user_input in ("0", "q", "Q"):
            print("👋 退出选择流程")
            return (0, None)
 
        try:
            choice = int(user_input)
            if 1 <= choice <= len(Controller.CheckPatterns.DesignPattern):
                selected_pattern = list(Controller.CheckPatterns.DesignPattern)[choice - 1]
                print(f"✅ 你选择了序号:{choice}(对应{selected_pattern._name_to_cn(selected_pattern.name)})")
                return (choice, selected_pattern)  # 返回(序列号, 枚举对象)
            else:
                print(f"❌ 输入无效!请输入1-{len(Controller.CheckPatterns.DesignPattern)}之间的数字,或0/q退出")
        except ValueError:
            print("❌ 输入无效!请输入数字序号,或0/q退出")
 
def ask_continue() -> bool:
    """
    询问用户是否继续选择,返回True(继续)/False(退出)
    """
    while True:
        user_choice = input("\n是否继续选择其他设计模式?(y/n):").strip().lower()
        if user_choice == "y":
            return True
        elif user_choice == "n":
            print("👋 感谢使用,程序结束!")
            return False
        else:
            print("❌ 输入无效!请输入 y(继续)或 n(退出)")
 
 
if __name__ == '__main__':
 
    # 方式1:用户输入选择展示(交互版)
    '''
    print("\n=== 方式1:用户选择展示 ===")
    print("可选设计模式:")
    for idx, pattern in enumerate( bll.CheckPatterns.DesignPattern, 1):
        print(f"{idx}. {pattern._name_to_cn(pattern.name)}({pattern.name})")
 
    try:
        choice = int(input("\n请输入序号选择要展示的设计模式:"))
        selected_pattern = list( bll.CheckPatterns.DesignPattern)[choice - 1]
        selected_pattern.show_example()
    except (ValueError, IndexError):
        print("❌ 输入无效,请输入正确的序号!")
    '''
    # 2
 
    print("🎉 设计模式示例展示程序")
    while True:
        # 1. 选择设计模式
        selected_num, selected_pattern = select_design_pattern()
 
        # 2. 判断是否直接退出(输入0/q)
        if selected_num == 0:
            print("👋 程序结束!")
            break
 
        # 3. 执行选中的示例
        selected_pattern.show_example()
        print(f"\n📌 本次选择的序列号是:{selected_num}")
 
        # 4. 询问是否继续
        if not ask_continue():
            break  # 用户选择不继续,终止循环
 
    print('hi,welcome geovindu.')

输出:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-06-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档