
agents24 之 python-design-patterns 技能详解从 KISS 到依赖注入的可维护 Python 架构指南【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents本篇技术指南围绕 agents24 仓库中plugins/python-development/skills/python-design-patterns技能展开系统讲解一套面向生产环境的 Python 设计原则KISS、单一职责、关注点分离、组合优于继承、三振出局Rule of Three、函数粒度控制、依赖注入以及常见反模式规避。文章完整继承该技能references/details.md的 8 个核心模式与全部可运行示例并结合SKILL.md的最佳实践清单、排查指南及仓库内相邻技能进行纵深扩充帮助你写出易于理解、测试与修改的 Python 代码。技能定位与适用场景python-design-patterns是 agents24 仓库中 python-development 插件体系下的核心技能之一。它在设计上采用导航层 详情层两级结构上层 SKILL.md 提供核心概念速览、快速上手代码与最佳实践摘要下层 references/details.md 提供完整的模式讲解与带注释的可运行示例。当导航层信息不足以支撑决策时Agent 或开发者应下沉阅读详情层。该技能的触发场景来自 SKILL.md覆盖了从设计到评审的全生命周期从零设计新服务或组件决定如何分层职责重构不断膨胀的上帝类God Class或巨型函数决定是新增抽象还是容忍重复评审 Pull Request 中的结构性缺陷紧耦合、内部类型泄露在新类层次结构中抉择继承与组合代码因 I/O 与业务逻辑纠缠而难以测试时。一句话概括技能的核心主张模式不是装饰而是解决真实问题的工具。它关注的是可维护性、可测试性与可读性而非堆砌设计模式的数量。四大基础模式模式 1KISS —— 保持简单在引入任何复杂度之前先问一句更简单的方案能否解决问题详情层文档给出的对照示例极具说服力。先看过度设计的写法——用带注册机制的工厂模式实现格式化器分发# Over-engineered: Factory with registration class OutputFormatterFactory: _formatters: dict[str, type[Formatter]] {} classmethod def register(cls, name: str): def decorator(formatter_cls): cls._formatters[name] formatter_cls return formatter_cls return decorator classmethod def create(cls, name: str) - Formatter: return cls._formatters[name]() OutputFormatterFactory.register(json) class JsonFormatter(Formatter): ...再看简单的写法——直接用一个字典# Simple: Just use a dictionary FORMATTERS { json: JsonFormatter, csv: CsvFormatter, xml: XmlFormatter, } def get_formatter(name: str) - Formatter: Get formatter by name. if name not in FORMATTERS: raise ValueError(fUnknown format: {name}) return FORMATTERS[name]()详情层给出的结论值得反复咀嚼The factory pattern adds code without adding value here. Save patterns for when they solve real problems.工厂模式在此处只增加代码而不增加价值把模式留到能解决真实问题的时候再用。这也呼应了 SKILL.md 的 Quick Start简单胜过花哨Simple beats clever。注意简单版本额外补了一个ValueError兜底——健壮性与简洁并不冲突。模式 2单一职责原则SRP每个类或函数应当只有一个变更理由reason to change。详情层用UserHandler给出了正反示例。反例——Handler 什么都做HTTP 解析、字段校验、数据库写入、响应格式化全部揉在一个async def create_user里# BAD: Handler does everything class UserHandler: async def create_user(self, request: Request) - Response: # HTTP parsing data await request.json() # Validation if not data.get(email): return Response({error: email required}, status400) # Database access user await db.execute( INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *, data[email], data[name] ) # Response formatting return Response({id: user.id, email: user.email}, status201)正例——拆分为两个职责清晰的类# GOOD: Separated concerns class UserService: Business logic only. def __init__(self, repo: UserRepository) - None: self._repo repo async def create_user(self, data: CreateUserInput) - User: # Only business rules here user User(emaildata.email, namedata.name) return await self._repo.save(user) class UserHandler: HTTP concerns only. def __init__(self, service: UserService) - None: self._service service async def create_user(self, request: Request) - Response: data CreateUserInput(**(await request.json())) user await self._service.create_user(data) return Response(user.to_dict(), status201)拆分后的收益如详情层所言HTTP 层的变化不会影响业务逻辑反之亦然Now HTTP changes dont affect business logic, and vice versa.。值得注意的细节是正例中的类型设计请求先经CreateUserInput数据类/Pydantic 模型转换再传入 Service——这为后续的在 API 边界尽早校验打好了基础与 python-anti-patterns 中缺失输入校验反模式的修复方案CreateUserInput.model_validate(data)形成呼应。模式 3关注点分离SoC将代码组织为职责明确的独立层次每一层只依赖其下层。详情层给出了经典的 API → Service → Repository 三层架构图┌─────────────────────────────────────────────────────┐ │ API Layer (handlers) │ │ - Parse requests │ │ - Call services │ │ - Format responses │ └─────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ Service Layer (business logic) │ │ - Domain rules and validation │ │ - Orchestrate operations │ │ - Pure functions where possible │ └─────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ Repository Layer (data access) │ │ - SQL queries │ │ - External API calls │ │ - Cache operations │ └─────────────────────────────────────────────────────┘API 层handlers解析请求、调用服务、格式化响应服务层业务逻辑领域规则与校验、操作编排、尽可能写成纯函数仓储层数据访问SQL 查询、外部 API 调用、缓存操作。配套的代码示例展示了每一层各司其职的完整形态# Repository: Data access class UserRepository: async def get_by_id(self, user_id: str) - User | None: row await self._db.fetchrow( SELECT * FROM users WHERE id $1, user_id ) return User(**row) if row else None # Service: Business logic class UserService: def __init__(self, repo: UserRepository) - None: self._repo repo async def get_user(self, user_id: str) - User: user await self._repo.get_by_id(user_id) if user is None: raise UserNotFoundError(user_id) return user # Handler: HTTP concerns app.get(/users/{user_id}) async def get_user(user_id: str) - UserResponse: user await user_service.get_user(user_id) return UserResponse.from_user(user)注意依赖箭头是单向向下的Service 可以 import Repository但 Repository 绝不能 import Handler。当出现服务层反向导入 API 层时就是明确的层次违规SKILL.md 的排查指南给出了修复方法引入一个共享的 types/models 层让两层共同依赖它从而保持依赖方向 API → Service → Repository。这一分层思想与仓库内 python-project-structure 技能中的 Pattern 6 Layered Architectureapi/、services/、repositories/、models/、schemas/、config/完全同构两个技能可以配合使用前者解决模块如何摆放后者解决类如何划分职责。模式 4组合优于继承通过组合对象来构建行为而不是通过继承扩展类。详情层以通知服务为例对比了两种方式。继承方式——僵硬且难以测试EmailNotificationService在__init__里直接SmtpClient()导致依赖难以 mock# Inheritance: Rigid and hard to test class EmailNotificationService(NotificationService): def __init__(self): super().__init__() self._smtp SmtpClient() # Hard to mock def notify(self, user: User, message: str) - None: self._smtp.send(user.email, message)组合方式——灵活且可测试所有依赖通过构造函数注入且各渠道是可选的# Composition: Flexible and testable class NotificationService: Send notifications via multiple channels. def __init__( self, email_sender: EmailSender, sms_sender: SmsSender | None None, push_sender: PushSender | None None, ) - None: self._email email_sender self._sms sms_sender self._push push_sender async def notify( self, user: User, message: str, channels: set[str] | None None, ) - None: channels channels or {email} if email in channels: await self._email.send(user.email, message) if sms in channels and self._sms and user.phone: await self._sms.send(user.phone, message) if push in channels and self._push and user.device_token: await self._push.send(user.device_token, message) # Easy to test with fakes service NotificationService( email_senderFakeEmailSender(), sms_senderFakeSmsSender(), )关键细节sms_sender与push_sender参数默认值为None配合if self._sms and user.phone的短路判断实现可选渠道的动态能力组合这在继承体系中通常要靠多层子类才能实现测试时直接注入FakeEmailSender、FakeSmsSender等替身fakes无需任何 mock 框架——这正是组合带来的可测试性红利。进阶模式模式 5三振出局Rule of Three等到出现第三个实例时再考虑抽象。详情层用订单处理与退货处理两个看起来相似的函数说明重复常常好过错误的抽象。# Two similar functions? Dont abstract yet def process_orders(orders: list[Order]) - list[Result]: results [] for order in orders: validated validate_order(order) result process_validated_order(validated) results.append(result) return results def process_returns(returns: list[Return]) - list[Result]: results [] for ret in returns: validated validate_return(ret) result process_validated_return(validated) results.append(result) return results # These look similar, but wait! Are they actually the same? # Different validation, different processing, different errors... # Duplication is often better than the wrong abstraction # Only after a third case, consider if theres a real pattern # But even then, sometimes explicit is better than abstract两个函数表面结构相同遍历 → 校验 → 处理 → 收集但校验逻辑、处理逻辑、错误语义各不相同。过早抽象会强行统一这些差异最终生成一个布满 if/else 分支的万能函数。只有出现第三个相似案例时才值得认真评估是否存在真正的共同模式——而且即便如此显式优于抽象explicit is better than abstract依然是值得保留的立场。SKILL.md 的排查指南补充了这条规则的边界条件Rule of Three 是启发式而非法律。如果重复的副本已经出现危险的分叉一处更新而另一处未更新导致 bug就应该立即抽象并补一个覆盖共享行为的测试。模式 6函数粒度控制保持函数聚焦。当函数出现以下信号时应考虑拆分超过 20-50 行视复杂度而定承担多个不同目的存在深层嵌套逻辑3 层及以上。详情层用订单处理函数演示了巨型函数 → 组合式函数的转变# Too long, multiple concerns mixed def process_order(order: Order) - Result: # 50 lines of validation... # 30 lines of inventory check... # 40 lines of payment processing... # 20 lines of notification... pass # Better: Composed from focused functions def process_order(order: Order) - Result: Process a customer order through the complete workflow. validate_order(order) reserve_inventory(order) payment_result charge_payment(order) send_confirmation(order, payment_result) return Result(successTrue, order_idorder.id)注意重构后的process_order保留了 docstringProcess a customer order through the complete workflow.这是关键组合式函数仍然有一个清晰的整体叙事只是把具体实现下放到各聚焦函数中。这一粒度标准与 python-project-structure 中单文件 300-500 行可考虑拆分的文件级标准互为补充——函数粒度管函数文件粒度管模块。模式 7依赖注入DI通过构造函数传递依赖以获得可测试性。详情层展示了一个同时注入repository、cache、logger三个依赖的完整示例并特别使用了typing.Protocol定义抽象依赖——这是现代 Python 中结构化子类型structural subtyping的典型应用from typing import Protocol class Logger(Protocol): def info(self, msg: str, **kwargs) - None: ... def error(self, msg: str, **kwargs) - None: ... class Cache(Protocol): async def get(self, key: str) - str | None: ... async def set(self, key: str, value: str, ttl: int) - None: ... class UserService: Service with injected dependencies. def __init__( self, repository: UserRepository, cache: Cache, logger: Logger, ) - None: self._repo repository self._cache cache self._logger logger async def get_user(self, user_id: str) - User: # Check cache first cached await self._cache.get(fuser:{user_id}) if cached: self._logger.info(Cache hit, user_iduser_id) return User.from_json(cached) # Fetch from database user await self._repo.get_by_id(user_id) if user: await self._cache.set(fuser:{user_id}, user.to_json(), ttl300) return user # Production service UserService( repositoryPostgresUserRepository(db), cacheRedisCache(redis), loggerStructlogLogger(), ) # Testing service UserService( repositoryInMemoryUserRepository(), cacheFakeCache(), loggerNullLogger(), )这个示例信息量很大值得逐点拆解Protocol 而非抽象基类Logger、Cache仅声明方法签名...占位不要求继承关系。任何具有get(key) - str | None等签名匹配的对象无论是否显式继承都满足Cache协议——测试中可以直接传FakeCache()同一套生产代码两套组装配置生产环境注入PostgresUserRepository、RedisCache、StructlogLogger测试环境注入InMemoryUserRepository、FakeCache、NullLogger。服务本身零改动——这就是依赖注入的核心价值缓存 日志的业务闭环get_user展示了缓存命中短路Cache hit日志 直接从 JSON 反序列化、缓存未命中回源数据库、成功后再回填缓存TTL 300 秒的完整流程跨技能印证这种构造器注入 每层隔离测试的结构正是 python-testing-patterns 技能中单元测试与 mock 策略得以实施的前提。值得注意的反模式信号SKILL.md当构造器参数膨胀到 7 个以上时这不是 DI 的问题而是该类职责过多的信号——应该先拆分类的职责构造函数自然会变小。模式 8规避常见反模式详情层在本节给出两组坏 / 好对照直指评审中最常见的两类结构性问题。不要暴露内部类型# BAD: Leaking ORM model to API app.get(/users/{id}) def get_user(id: str) - UserModel: # SQLAlchemy model return db.query(UserModel).get(id) # GOOD: Use response schemas app.get(/users/{id}) def get_user(id: str) - UserResponse: user db.query(UserModel).get(id) return UserResponse.from_orm(user)将 SQLAlchemy 模型直接作为 API 返回值会把数据库层的字段、延迟加载行为、内部命名全部泄露给客户端。正确做法是通过响应模式response schema显式定义对外契约。这与 python-anti-patterns 中的 Exposed Internal Types 反模式完全一致其修复建议同样是 DTO/response models如UserResponse.from_orm(user)。不要把 I/O 与业务逻辑混在一起# BAD: SQL embedded in business logic def calculate_discount(user_id: str) - float: user db.query(SELECT * FROM users WHERE id ?, user_id) orders db.query(SELECT * FROM orders WHERE user_id ?, user_id) # Business logic mixed with data access # GOOD: Repository pattern def calculate_discount(user: User, order_history: list[Order]) - float: # Pure business logic, easily testable if len(order_history) 10: return 0.15 return 0.0重构后的calculate_discount接收user与order_history两个已就绪的参数返回纯计算结果超过 10 笔订单打 8.5 折否则无折扣——不碰数据库、不做 I/O因此可以脱离数据库环境进行单元测试。这正是详情层三层架构中Service Layer 尽可能写纯函数原则的具体落地。最佳实践清单与排查指南SKILL.md 在详情层之上给出了十条可执行的最佳实践摘要可作为日常开发的 checklist保持简单——选择能工作的最简单方案单一职责——每个单元只有一个变更理由关注点分离——层次清晰、目的明确组合而非继承——组合对象换取灵活性三振出局——抽象前先等待保持函数短小——20-50 行视复杂度而定一个目的注入依赖——构造器注入换取可测试性先删后抽象——先删除死代码再考虑模式逐层测试——每个关注点独立测试显式优于聪明——可读代码胜过优雅代码。其中第 8 条Delete before abstracting是常被忽略的一步重构前先清理死代码往往能让是否需要抽象的答案自动浮现。针对实际落地中最常见的困惑SKILL.md 提供了五组 QA 排查指南Q1类在膨胀、似乎有多重职责但拆分感觉不对。应用变更理由测试列出所有可能导致该类被修改的原因。如果列表中的条目来自不同领域如 HTTP 解析 AND 业务规则 AND 格式化就拆分如果全部来自同一领域关注点类的大小可能是合适的。Q2构造器注入导致构造器参数超过 7 个。这是类职责过多的信号而非 DI 的问题。先拆分大类各子类构造器自然变小。Q3组合产生了深层的包装对象难以追踪。保持组合浅层2-3 层。如果包装是唯一手段考虑基于 Protocol 的方案或简单函数组合而不是装饰器对象链。Q4Rule of Three 说不该抽象但重复正因一处更新另一处没更而产生 bug。危险分叉的重复应当提前抽象。Rule of Three 是启发式而非法律若副本已经错误分叉立即抽取并补一个覆盖共享行为的测试。Q5服务层从 API 层导入打破了依赖方向。这是层次违规。服务层不得从 handlers 导入应引入共享的 types/models 层供两层共同依赖保持 API → Service → Repository 的向下依赖箭头。技能在仓库中的协同定位python-design-patterns并非孤岛它与仓库内多个相邻技能形成完整的 Python 工程实践闭环python-anti-patterns与本文档构成正反对照。其文档开头即注明本技能聚焦于该避免什么关于正面模式与架构请见 python-design-patterns 技能。两个技能可配合用于评审前者当 checklist 排查问题后者提供修复所需的正面模式python-project-structure解决模块组织与目录布局让本技能的层次边界API/Service/Repository在工程结构上显式化python-testing-patterns其文档同样将本技能列为前置——利用这里建立的依赖注入结构逐层隔离测试。DI 是测试隔离的前提测试是验证 DI 结构的试金石python-pro该 Agent 负责将上述技能落地为生产级代码强调 PEP 8、类型注解、全面错误处理、90% 测试覆盖率与标准库优先与设计模式技能的理念一致。此外python-type-safety、python-error-handling 等技能也与本文档的 Protocol 类型、异常设计等内容存在天然关联。结语模式的正确打开方式回到详情层开篇的立场模式的价值在于解决真实问题。KISS 提醒你别为了模式而模式——字典能解决的问题不需要工厂SRP 与 SoC 保证每一层、每个类都有清晰且单一的变更理由组合优于继承让系统在测试与扩展时保持弹性Rule of Three 与函数粒度控制防止过早抽象与巨型函数依赖注入把可测试性建立在结构之上而反模式规避则守住架构的底线。这套技能的最终评判标准是 SKILL.md 中反复强调的三维目标易于理解easy to understand、易于测试easy to test、易于修改easy to modify。当你下次设计新服务、重构上帝类或评审 PR 时不妨逐条对照本文的模式与排查指南让设计决策有据可依。【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考