@umacloud/knowledge 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (418) hide show
  1. package/00-governance/governance-capabilities.md +557 -0
  2. package/00-governance/knowledge-map.md +39 -0
  3. package/00-governance/maintenance-policy.md +76 -0
  4. package/00-governance/review-checklist.md +81 -0
  5. package/README.md +13 -0
  6. package/ai/01-standards/agent-development-complete.md +691 -0
  7. package/ai/01-standards/llm-application-complete.md +488 -0
  8. package/ai/01-standards/mlops-complete.md +798 -0
  9. package/ai/01-standards/prompt-engineering-complete.md +646 -0
  10. package/ai/01-standards/rag-architecture-complete.md +649 -0
  11. package/ai/02-playbooks/llm-evaluation-playbook.md +847 -0
  12. package/ai/03-checklists/ai-project-checklist.md +215 -0
  13. package/ai/04-antipatterns/ai-antipatterns.md +661 -0
  14. package/ai/05-cases/case-rag-production.md +147 -0
  15. package/ai/06-glossary/ai-glossary.md +162 -0
  16. package/ai/agent-evaluation-benchmark.md +53 -0
  17. package/ai/ai-agent-memory-context-management.md +41 -0
  18. package/ai/ai-cost-capacity-optimization-playbook.md +42 -0
  19. package/ai/ai-data-security-and-compliance-playbook.md +37 -0
  20. package/ai/ai-domain-index-and-checklist.md +40 -0
  21. package/ai/ai-governance-maturity-model.md +50 -0
  22. package/ai/ai-model-selection-and-routing-strategy.md +47 -0
  23. package/ai/ai-observability-and-oncall-runbook.md +52 -0
  24. package/ai/ai-rag-engineering-playbook.md +42 -0
  25. package/ai/ai-red-team-and-safety-evaluation.md +42 -0
  26. package/ai/ai-release-readiness-and-rollback-gate.md +42 -0
  27. package/ai/llm-agent-engineering-deep-dive.md +57 -0
  28. package/ai/prompt-and-tool-guardrails.md +52 -0
  29. package/api/01-standards/enterprise-api-standards.md +198 -0
  30. package/api/01-standards/rest-api-design-guide.md +63 -0
  31. package/api/02-playbooks/api-pagination-playbook.md +93 -0
  32. package/api/02-playbooks/graphql-production-playbook.md +176 -0
  33. package/api/03-checklists/api-review-checklist.md +55 -0
  34. package/api/04-antipatterns/api-antipatterns.md +112 -0
  35. package/architecture/01-standards/api-gateway-patterns.md +496 -0
  36. package/architecture/01-standards/cloud-native-patterns.md +644 -0
  37. package/architecture/01-standards/distributed-systems-patterns.md +591 -0
  38. package/architecture/01-standards/event-driven-architecture.md +595 -0
  39. package/architecture/01-standards/microservices-patterns-complete.md +968 -0
  40. package/architecture/01-standards/microservices-patterns.md +495 -0
  41. package/architecture/01-standards/system-design-interview.md +664 -0
  42. package/architecture/02-playbooks/microservices-patterns-playbook.md +137 -0
  43. package/architecture/02-playbooks/migration-playbook.md +780 -0
  44. package/architecture/02-playbooks/system-design-playbook.md +779 -0
  45. package/architecture/03-checklists/architecture-decision-checklist.md +297 -0
  46. package/architecture/04-antipatterns/architecture-antipatterns.md +417 -0
  47. package/architecture/05-cases/case-netflix-microservices.md +413 -0
  48. package/architecture/06-glossary/architecture-glossary.md +164 -0
  49. package/architecture/adr-template-and-examples.md +38 -0
  50. package/architecture/api-gateway-deep-dive.md +1291 -0
  51. package/architecture/configuration-management.md +1162 -0
  52. package/architecture/distributed-transactions.md +1220 -0
  53. package/architecture/microservices-complete.md +735 -0
  54. package/architecture/resilience-and-disaster-patterns.md +37 -0
  55. package/architecture/service-governance.md +1198 -0
  56. package/architecture/system-architecture-deep-dive.md +37 -0
  57. package/backend/01-standards/analytics-and-growth.md +65 -0
  58. package/backend/01-standards/api-and-error-conventions.md +120 -0
  59. package/backend/01-standards/application-layering-and-packaging.md +160 -0
  60. package/backend/01-standards/auth-implementation.md +104 -0
  61. package/backend/01-standards/backend-framework-idioms.md +74 -0
  62. package/backend/01-standards/background-jobs-and-async.md +66 -0
  63. package/backend/01-standards/caching-strategies-complete.md +390 -0
  64. package/backend/01-standards/config-and-observability.md +77 -0
  65. package/backend/01-standards/data-modeling-and-persistence.md +94 -0
  66. package/backend/01-standards/django-complete.md +1765 -0
  67. package/backend/01-standards/email-and-notifications.md +64 -0
  68. package/backend/01-standards/fastapi-complete.md +925 -0
  69. package/backend/01-standards/file-upload-and-storage.md +66 -0
  70. package/backend/01-standards/graphql-api-complete.md +416 -0
  71. package/backend/01-standards/llm-application-standard.md +78 -0
  72. package/backend/01-standards/message-queue-patterns.md +379 -0
  73. package/backend/01-standards/microservices-and-distributed.md +78 -0
  74. package/backend/01-standards/nestjs-complete.md +2167 -0
  75. package/backend/01-standards/payment-integration.md +80 -0
  76. package/backend/01-standards/rate-limiting-complete.md +451 -0
  77. package/backend/01-standards/realtime-and-websocket.md +65 -0
  78. package/backend/01-standards/search-and-filtering.md +64 -0
  79. package/backend/01-standards/spring-boot-complete.md +445 -0
  80. package/backend/02-playbooks/api-design-playbook.md +718 -0
  81. package/backend/02-playbooks/email-send-playbook.md +130 -0
  82. package/backend/02-playbooks/file-upload-s3-playbook.md +153 -0
  83. package/backend/02-playbooks/typescript-enterprise-playbook.md +133 -0
  84. package/backend/02-playbooks/websocket-realtime-playbook.md +154 -0
  85. package/backend/03-checklists/api-launch-checklist.md +189 -0
  86. package/backend/04-antipatterns/backend-antipatterns.md +1051 -0
  87. package/blockchain/01-standards/blockchain-basics.md +557 -0
  88. package/blockchain/01-standards/smart-contract-development.md +1315 -0
  89. package/cicd/01-standards/deployment-and-delivery-standard.md +96 -0
  90. package/cicd/01-standards/github-actions-complete.md +473 -0
  91. package/cicd/01-standards/release-and-store-submission.md +75 -0
  92. package/cicd/02-playbooks/cicd-pipeline-playbook.md +144 -0
  93. package/cicd/02-playbooks/release-management-playbook.md +605 -0
  94. package/cicd/03-checklists/pipeline-security-checklist.md +168 -0
  95. package/cicd/04-antipatterns/cicd-antipatterns.md +589 -0
  96. package/cicd/05-cases/case-deployment-automation.md +221 -0
  97. package/cicd/05-cases/case-gitops-transformation.md +212 -0
  98. package/cicd/06-glossary/cicd-glossary.md +114 -0
  99. package/cicd/cicd-blueprint-deep-dive.md +38 -0
  100. package/cicd/release-readiness-gate.md +37 -0
  101. package/cloud-native/01-standards/container-security.md +741 -0
  102. package/cloud-native/01-standards/kubernetes-complete.md +812 -0
  103. package/cloud-native/02-playbooks/api-gateway-playbook.md +155 -0
  104. package/cloud-native/02-playbooks/gitops-with-argocd.md +760 -0
  105. package/cloud-native/02-playbooks/k8s-troubleshooting-playbook.md +1942 -0
  106. package/cloud-native/02-playbooks/message-queue-playbook.md +129 -0
  107. package/cloud-native/02-playbooks/multicloud-governance.md +726 -0
  108. package/cloud-native/02-playbooks/serverless-patterns.md +788 -0
  109. package/cloud-native/02-playbooks/service-mesh-playbook.md +612 -0
  110. package/cloud-native/02-playbooks/terraform-iac-playbook.md +143 -0
  111. package/cloud-native/03-checklists/container-security-checklist.md +431 -0
  112. package/cloud-native/03-checklists/k8s-production-readiness-checklist.md +460 -0
  113. package/cloud-native/04-antipatterns/container-antipatterns.md +660 -0
  114. package/cloud-native/04-antipatterns/k8s-antipatterns.md +743 -0
  115. package/cloud-native/05-cases/case-k8s-migration.md +478 -0
  116. package/cloud-native/05-cases/case-k8s-scaling.md +642 -0
  117. package/cloud-native/05-cases/case-k8s-security-incident.md +397 -0
  118. package/cloud-native/06-glossary/cloud-native-glossary.md +337 -0
  119. package/cross-platform/01-standards/cross-platform-frameworks.md +83 -0
  120. package/cross-platform/01-standards/platform-selection-and-architecture.md +77 -0
  121. package/data/01-standards/elasticsearch-complete.md +2098 -0
  122. package/data/01-standards/postgresql-complete.md +1613 -0
  123. package/data/01-standards/redis-complete.md +1527 -0
  124. package/data/02-playbooks/database-optimization-playbook.md +403 -0
  125. package/data/02-playbooks/elasticsearch-production-playbook.md +132 -0
  126. package/data/03-checklists/database-launch-checklist.md +187 -0
  127. package/data/04-antipatterns/database-antipatterns.md +873 -0
  128. package/data/05-cases/case-database-migration.md +310 -0
  129. package/data/06-glossary/database-glossary.md +440 -0
  130. package/data/data-governance-and-modeling-deep-dive.md +39 -0
  131. package/data-engineering/01-standards/airflow-complete.md +523 -0
  132. package/data-engineering/01-standards/kafka-complete.md +1521 -0
  133. package/data-engineering/02-playbooks/spark-etl-playbook.md +496 -0
  134. package/data-engineering/03-checklists/pipeline-launch-checklist.md +194 -0
  135. package/data-engineering/04-antipatterns/data-pipeline-antipatterns.md +684 -0
  136. package/data-engineering/05-cases/case-real-time-pipeline.md +355 -0
  137. package/data-engineering/06-glossary/data-engineering-glossary.md +429 -0
  138. package/database/01-standards/database-schema-standards.md +147 -0
  139. package/database/02-playbooks/postgresql-optimization-quick.md +52 -0
  140. package/database/02-playbooks/postgresql-performance-optimization.md +58 -0
  141. package/database/02-playbooks/postgresql-production-playbook.md +146 -0
  142. package/database/02-playbooks/redis-caching-playbook.md +117 -0
  143. package/database/03-checklists/database-review-checklist.md +50 -0
  144. package/database/04-antipatterns/database-antipatterns.md +112 -0
  145. package/design/01-standards/ui-design-system-complete.md +423 -0
  146. package/design/02-playbooks/design-handoff-playbook.md +254 -0
  147. package/design/02-playbooks/design-review-playbook.md +388 -0
  148. package/design/03-checklists/design-review-checklist.md +246 -0
  149. package/design/04-antipatterns/design-antipatterns.md +378 -0
  150. package/design/05-cases/case-design-system-adoption.md +328 -0
  151. package/design/06-glossary/design-glossary.md +329 -0
  152. package/design/ui-full-lifecycle-cross-platform-playbook.md +571 -0
  153. package/design/ux-system-deep-dive.md +38 -0
  154. package/design-systems/00-craft-rules.md +71 -0
  155. package/design-systems/aesthetic-families.md +43 -0
  156. package/design-systems/anti-ai-slop.md +162 -0
  157. package/design-systems/bold-geometric.md +120 -0
  158. package/design-systems/brutalist-bold.md +103 -0
  159. package/design-systems/editorial-clean.md +109 -0
  160. package/design-systems/glass-aurora.md +108 -0
  161. package/design-systems/modern-minimal.md +145 -0
  162. package/design-systems/premium-luxury.md +106 -0
  163. package/design-systems/product-type-design-map.md +48 -0
  164. package/design-systems/soft-warm.md +123 -0
  165. package/design-systems/tech-utility.md +113 -0
  166. package/desktop/01-standards/desktop-app-standard.md +72 -0
  167. package/desktop/01-standards/desktop-design.md +71 -0
  168. package/development/00-governance/document-template.md +41 -0
  169. package/development/01-standards/api-versioning-strategies.md +432 -0
  170. package/development/01-standards/authentication-patterns-complete.md +479 -0
  171. package/development/01-standards/css-architecture-complete.md +550 -0
  172. package/development/01-standards/database-migration-strategies.md +484 -0
  173. package/development/01-standards/elasticsearch-complete.md +347 -0
  174. package/development/01-standards/git-complete.md +371 -0
  175. package/development/01-standards/golang-complete.md +1565 -0
  176. package/development/01-standards/graphql-complete.md +298 -0
  177. package/development/01-standards/javascript-bundlers-complete.md +469 -0
  178. package/development/01-standards/javascript-typescript-complete.md +528 -0
  179. package/development/01-standards/jest-complete.md +275 -0
  180. package/development/01-standards/linux-complete.md +234 -0
  181. package/development/01-standards/logging-observability-complete.md +526 -0
  182. package/development/01-standards/microservices-communication.md +502 -0
  183. package/development/01-standards/mongodb-complete.md +406 -0
  184. package/development/01-standards/oauth2-complete.md +285 -0
  185. package/development/01-standards/performance-optimization-complete.md +289 -0
  186. package/development/01-standards/playwright-complete.md +247 -0
  187. package/development/01-standards/postgresql-complete.md +456 -0
  188. package/development/01-standards/pytest-complete.md +340 -0
  189. package/development/01-standards/python-async-programming.md +902 -0
  190. package/development/01-standards/python-complete.md +956 -0
  191. package/development/01-standards/python-decorators-complete.md +799 -0
  192. package/development/01-standards/python-design-patterns.md +2854 -0
  193. package/development/01-standards/python-packaging-distribution.md +420 -0
  194. package/development/01-standards/python-testing-strategies.md +607 -0
  195. package/development/01-standards/python-web-frameworks-comparison.md +471 -0
  196. package/development/01-standards/redis-complete.md +317 -0
  197. package/development/01-standards/rest-api-complete.md +316 -0
  198. package/development/01-standards/rust-complete.md +578 -0
  199. package/development/01-standards/typescript-advanced-types.md +1513 -0
  200. package/development/01-standards/web-security-complete.md +292 -0
  201. package/development/02-playbooks/api-design-playbook.md +810 -0
  202. package/development/02-playbooks/database-migration-playbook.md +580 -0
  203. package/development/02-playbooks/debugging-playbook.md +692 -0
  204. package/development/02-playbooks/feature-delivery-playbook.md +430 -0
  205. package/development/02-playbooks/incident-hotfix-playbook.md +387 -0
  206. package/development/02-playbooks/performance-optimization-playbook.md +531 -0
  207. package/development/02-playbooks/performance-tuning-playbook.md +652 -0
  208. package/development/02-playbooks/refactor-playbook.md +403 -0
  209. package/development/02-playbooks/release-playbook.md +469 -0
  210. package/development/03-checklists/architecture-review-checklist.md +168 -0
  211. package/development/03-checklists/data-migration-checklist.md +157 -0
  212. package/development/03-checklists/oncall-handover-checklist.md +173 -0
  213. package/development/03-checklists/pr-checklist.md +158 -0
  214. package/development/03-checklists/production-readiness-checklist.md +190 -0
  215. package/development/03-checklists/release-readiness-checklist.md +154 -0
  216. package/development/03-checklists/security-review-checklist.md +182 -0
  217. package/development/04-antipatterns/api-antipatterns.md +657 -0
  218. package/development/04-antipatterns/architecture-antipatterns.md +686 -0
  219. package/development/04-antipatterns/backend-antipatterns.md +648 -0
  220. package/development/04-antipatterns/cicd-antipatterns.md +540 -0
  221. package/development/04-antipatterns/code-smell-antipatterns.md +571 -0
  222. package/development/04-antipatterns/data-antipatterns.md +658 -0
  223. package/development/04-antipatterns/database-antipatterns.md +578 -0
  224. package/development/04-antipatterns/frontend-antipatterns.md +635 -0
  225. package/development/04-antipatterns/reliability-antipatterns.md +700 -0
  226. package/development/04-antipatterns/security-antipatterns.md +747 -0
  227. package/development/05-cases/case-api-version-migration.md +428 -0
  228. package/development/05-cases/case-authorization-hardening.md +383 -0
  229. package/development/05-cases/case-bluegreen-rollback.md +466 -0
  230. package/development/05-cases/case-cache-snowball-protection.md +485 -0
  231. package/development/05-cases/case-ci-cd-pipeline.md +544 -0
  232. package/development/05-cases/case-database-scaling.md +500 -0
  233. package/development/05-cases/case-db-hotspot-optimization.md +487 -0
  234. package/development/05-cases/case-incident-mttr-reduction.md +563 -0
  235. package/development/05-cases/case-microservice-migration.md +375 -0
  236. package/development/05-cases/case-performance-optimization.md +406 -0
  237. package/development/05-cases/case-security-incident-response.md +345 -0
  238. package/development/06-glossary/full-stack-glossary.md +166 -0
  239. package/development/09-maturity/quarterly-audit-template.md +35 -0
  240. package/development/11-ui-excellence/ui-aesthetic-system.md +41 -0
  241. package/development/11-ui-excellence/ui-engineering-excellence.md +435 -0
  242. package/development/12-scenarios/development-scenarios-guide.md +565 -0
  243. package/development/13-implementation-assets/implementation-toolkit.md +282 -0
  244. package/development/13-implementation-assets/knowledge-gates-execution.md +43 -0
  245. package/development/14-full-lifecycle/software-lifecycle-gates.md +511 -0
  246. package/development/15-lifecycle-templates/project-templates-collection.md +791 -0
  247. package/development/api-contract-and-versioning-guide.md +36 -0
  248. package/development/api-governance-complete.md +43 -0
  249. package/development/backend-engineering-complete.md +43 -0
  250. package/development/code-review-quality-complete.md +43 -0
  251. package/development/concurrency-reliability-complete.md +43 -0
  252. package/development/database-engineering-complete.md +43 -0
  253. package/development/engineering-effectiveness-complete.md +43 -0
  254. package/development/engineering-standards-deep-dive.md +38 -0
  255. package/development/frontend-engineering-complete.md +43 -0
  256. package/development/performance-capacity-complete.md +43 -0
  257. package/development/refactor-migration-complete.md +42 -0
  258. package/development/refactoring-and-techdebt-playbook.md +37 -0
  259. package/development/security-in-development-complete.md +43 -0
  260. package/devops/01-standards/cicd-pipeline-complete.md +262 -0
  261. package/devops/01-standards/docker-complete.md +1490 -0
  262. package/devops/01-standards/github-actions-complete.md +337 -0
  263. package/devops/01-standards/kubernetes-complete.md +638 -0
  264. package/devops/01-standards/terraform-complete.md +2117 -0
  265. package/devops/02-playbooks/docker-compose-playbook.md +233 -0
  266. package/devops/02-playbooks/docker-k8s-production-playbook.md +186 -0
  267. package/devops/02-playbooks/docker-production-playbook.md +952 -0
  268. package/edge-iot/01-standards/edge-iot-complete.md +473 -0
  269. package/experts/architect/api-design.md +178 -0
  270. package/experts/architect/methodology.md +124 -0
  271. package/experts/architect/security.md +75 -0
  272. package/experts/backend-lead/methodology.md +216 -0
  273. package/experts/devops/methodology.md +160 -0
  274. package/experts/frontend-lead/methodology.md +178 -0
  275. package/experts/product-manager/industry/ecommerce.md +43 -0
  276. package/experts/product-manager/industry/saas.md +40 -0
  277. package/experts/product-manager/methodology.md +97 -0
  278. package/experts/qa-lead/methodology.md +123 -0
  279. package/experts/qa-lead/test-strategy.md +128 -0
  280. package/experts/uiux-designer/methodology.md +125 -0
  281. package/frontend/01-standards/accessibility-complete.md +532 -0
  282. package/frontend/01-standards/accessibility-standard.md +74 -0
  283. package/frontend/01-standards/admin-dashboard-and-crud.md +72 -0
  284. package/frontend/01-standards/design-tokens-complete.md +444 -0
  285. package/frontend/01-standards/forms-and-validation.md +77 -0
  286. package/frontend/01-standards/frontend-architecture-and-layering.md +119 -0
  287. package/frontend/01-standards/i18n-and-localization.md +65 -0
  288. package/frontend/01-standards/nextjs-complete.md +451 -0
  289. package/frontend/01-standards/react-complete.md +713 -0
  290. package/frontend/01-standards/react-hooks-complete-guide.md +1100 -0
  291. package/frontend/01-standards/react-hooks-complete.md +1171 -0
  292. package/frontend/01-standards/seo-and-web-vitals.md +77 -0
  293. package/frontend/01-standards/state-management-complete.md +444 -0
  294. package/frontend/01-standards/vue-complete.md +499 -0
  295. package/frontend/01-standards/vue3-complete.md +2002 -0
  296. package/frontend/01-standards/web-framework-best-practices.md +64 -0
  297. package/frontend/01-standards/web-performance-complete.md +495 -0
  298. package/frontend/02-playbooks/accessibility-a11y-playbook.md +161 -0
  299. package/frontend/02-playbooks/frontend-performance-playbook.md +707 -0
  300. package/frontend/02-playbooks/i18n-internationalization-playbook.md +120 -0
  301. package/frontend/02-playbooks/performance-optimization-playbook.md +163 -0
  302. package/frontend/02-playbooks/react-nextjs-production-playbook.md +167 -0
  303. package/frontend/02-playbooks/react-state-management-playbook.md +173 -0
  304. package/frontend/03-checklists/component-quality-checklist.md +166 -0
  305. package/frontend/03-checklists/frontend-launch-checklist.md +299 -0
  306. package/frontend/04-antipatterns/frontend-antipatterns.md +886 -0
  307. package/frontend/05-cases/case-performance-optimization.md +274 -0
  308. package/harmony/01-standards/harmonyos-arkts-standard.md +75 -0
  309. package/harmony/01-standards/harmonyos-design.md +65 -0
  310. package/high-quality-engineering-playbook.md +54 -0
  311. package/incident/01-standards/incident-response-complete.md +303 -0
  312. package/incident/02-playbooks/chaos-engineering-playbook.md +883 -0
  313. package/incident/02-playbooks/postmortem-playbook.md +398 -0
  314. package/incident/03-checklists/incident-readiness-checklist.md +181 -0
  315. package/incident/04-antipatterns/incident-antipatterns.md +490 -0
  316. package/incident/05-cases/case-cascade-failure.md +176 -0
  317. package/incident/06-glossary/incident-glossary.md +114 -0
  318. package/incident/postmortem-and-response-deep-dive.md +39 -0
  319. package/industries/ecommerce/ecommerce-complete.md +631 -0
  320. package/industries/education/education-complete.md +555 -0
  321. package/industries/fintech/fintech-complete.md +501 -0
  322. package/industries/gaming/gaming-complete.md +587 -0
  323. package/industries/healthcare/healthcare-complete.md +452 -0
  324. package/low-code/01-standards/low-code-complete.md +944 -0
  325. package/miniprogram/01-standards/ai-common-mistakes.md +61 -0
  326. package/miniprogram/01-standards/miniprogram-custom-navbar-capsule.md +77 -0
  327. package/miniprogram/01-standards/miniprogram-design.md +61 -0
  328. package/miniprogram/01-standards/miniprogram-standard.md +81 -0
  329. package/mobile/01-standards/android-material-design.md +70 -0
  330. package/mobile/01-standards/flutter-complete.md +384 -0
  331. package/mobile/01-standards/ios-design-hig.md +78 -0
  332. package/mobile/01-standards/mobile-app-standard.md +85 -0
  333. package/mobile/01-standards/react-native-complete.md +352 -0
  334. package/mobile/02-playbooks/mobile-cross-platform-playbook.md +175 -0
  335. package/mobile/02-playbooks/mobile-performance.md +473 -0
  336. package/mobile/03-checklists/mobile-release-checklist.md +234 -0
  337. package/mobile/04-antipatterns/mobile-antipatterns.md +798 -0
  338. package/mobile/05-cases/case-app-performance.md +500 -0
  339. package/mobile/05-cases/case-app-startup-optimization.md +218 -0
  340. package/mobile/06-glossary/mobile-glossary.md +484 -0
  341. package/observability/01-standards/observability-standards.md +103 -0
  342. package/observability/02-playbooks/prometheus-grafana-playbook.md +135 -0
  343. package/observability/02-playbooks/structured-logging-playbook.md +73 -0
  344. package/observability/03-checklists/observability-checklist.md +54 -0
  345. package/observability/04-antipatterns/observability-antipatterns.md +106 -0
  346. package/operations/01-standards/prometheus-monitoring-complete.md +1578 -0
  347. package/operations/02-playbooks/capacity-planning-playbook.md +620 -0
  348. package/operations/03-checklists/production-launch-checklist.md +365 -0
  349. package/operations/04-antipatterns/operations-antipatterns.md +664 -0
  350. package/operations/05-cases/case-sre-practices.md +581 -0
  351. package/operations/06-glossary/operations-glossary.md +120 -0
  352. package/operations/aiops-anomaly-detection.md +758 -0
  353. package/operations/capacity-planning.md +1061 -0
  354. package/operations/chaos-engineering.md +659 -0
  355. package/operations/incident-command-system.md +38 -0
  356. package/operations/observability-complete.md +442 -0
  357. package/operations/slo-sli-playbook.md +517 -0
  358. package/operations/sre-operations-deep-dive.md +39 -0
  359. package/package.json +8 -0
  360. package/performance/01-standards/performance-and-scalability.md +80 -0
  361. package/performance/01-standards/performance-standards.md +156 -0
  362. package/performance/02-playbooks/query-optimization-playbook.md +103 -0
  363. package/performance/03-checklists/performance-checklist.md +56 -0
  364. package/performance/04-antipatterns/performance-antipatterns.md +146 -0
  365. package/product/01-standards/product-management-complete.md +285 -0
  366. package/product/02-playbooks/feature-launch-playbook.md +207 -0
  367. package/product/02-playbooks/user-research-playbook.md +532 -0
  368. package/product/03-checklists/feature-launch-checklist.md +275 -0
  369. package/product/04-antipatterns/product-antipatterns.md +355 -0
  370. package/product/05-cases/case-mvp-to-scale.md +384 -0
  371. package/product/06-glossary/product-glossary.md +462 -0
  372. package/product/feature-prioritization-framework.md +40 -0
  373. package/product/kpi-and-metric-tree.md +37 -0
  374. package/product/product-discovery-and-prd-deep-dive.md +41 -0
  375. package/quantum/01-standards/quantum-complete.md +1186 -0
  376. package/security/01-standards/api-security-complete.md +511 -0
  377. package/security/01-standards/container-runtime-security.md +574 -0
  378. package/security/01-standards/data-protection-gdpr.md +543 -0
  379. package/security/01-standards/owasp-top10-complete.md +1890 -0
  380. package/security/01-standards/secure-coding-baseline.md +90 -0
  381. package/security/01-standards/supply-chain-security.md +441 -0
  382. package/security/01-standards/web-security-checklist.md +108 -0
  383. package/security/01-standards/zero-trust-architecture.md +521 -0
  384. package/security/02-playbooks/auth-sso-playbook.md +166 -0
  385. package/security/02-playbooks/incident-response-security-playbook.md +588 -0
  386. package/security/02-playbooks/owasp-api-security-playbook.md +129 -0
  387. package/security/02-playbooks/payment-integration-playbook.md +119 -0
  388. package/security/02-playbooks/penetration-testing-playbook.md +517 -0
  389. package/security/03-checklists/security-audit-checklist.md +356 -0
  390. package/security/04-antipatterns/security-coding-antipatterns.md +580 -0
  391. package/security/05-cases/case-log4shell-incident.md +537 -0
  392. package/security/05-cases/case-major-breaches.md +468 -0
  393. package/security/06-glossary/security-glossary.md +212 -0
  394. package/security/compliance-automation.md +993 -0
  395. package/security/container-security.md +680 -0
  396. package/security/devsecops-complete.md +426 -0
  397. package/security/sast-dast-sca.md +775 -0
  398. package/security/secrets-management.md +594 -0
  399. package/security/security-architecture-deep-dive.md +37 -0
  400. package/security/threat-modeling-stride-playbook.md +40 -0
  401. package/seed-templates/auth-system.md +59 -0
  402. package/seed-templates/blog-content.md +94 -0
  403. package/seed-templates/dashboard.md +89 -0
  404. package/seed-templates/docs-site.md +73 -0
  405. package/seed-templates/e-commerce.md +50 -0
  406. package/seed-templates/saas-landing.md +92 -0
  407. package/seed-templates/settings-page.md +51 -0
  408. package/testing/01-standards/test-strategy-and-layering.md +83 -0
  409. package/testing/01-standards/testing-strategy-complete.md +422 -0
  410. package/testing/01-standards/unit-testing-best-practices.md +118 -0
  411. package/testing/02-playbooks/e2e-testing-playbook.md +988 -0
  412. package/testing/02-playbooks/testing-strategy-playbook.md +126 -0
  413. package/testing/03-checklists/test-strategy-checklist.md +208 -0
  414. package/testing/04-antipatterns/testing-antipatterns.md +718 -0
  415. package/testing/05-cases/case-testing-transformation.md +300 -0
  416. package/testing/06-glossary/testing-glossary.md +110 -0
  417. package/testing/risk-based-test-matrix.md +36 -0
  418. package/testing/testing-strategy-deep-dive.md +37 -0
@@ -0,0 +1,2854 @@
1
+ ---
2
+ id: python-design-patterns
3
+ title: Python设计模式完整知识体系
4
+ domain: development
5
+ category: 01-standards
6
+ difficulty: intermediate
7
+ tags: [agent, checklist, design, development, patterns, python, python特有模式, 创建型模式]
8
+ quality_score: 70
9
+ last_updated: 2026-06-15
10
+ ---
11
+ # Python设计模式完整知识体系
12
+
13
+ ## 概述
14
+
15
+ 设计模式是解决反复出现的软件设计问题的可复用方案。Python因其动态类型、一等函数、鸭子类型和丰富的内置协议,使得许多传统GoF模式在Python中有更简洁、更惯用的实现方式。
16
+
17
+ ### Python设计模式的特殊性
18
+
19
+ - **一等函数替代策略/命令类层次**: Python函数是一等公民,许多需要单方法接口的模式可直接用函数或callable对象实现
20
+ - **鸭子类型替代接口**: 无需显式接口声明,依赖协议(Protocol)和结构化子类型
21
+ - **装饰器语法糖**: Python内置的`@decorator`语法让装饰器模式成为语言特性
22
+ - **元类和描述符**: 提供Java/C++中不存在的元编程能力
23
+ - **上下文管理器协议**: `with`语句为资源管理提供标准化模式
24
+ - **dataclass和NamedTuple**: 极大简化值对象和数据传输对象的创建
25
+
26
+ ### Python惯用法 vs 传统GoF模式
27
+
28
+ | GoF模式 | Java实现 | Python惯用实现 |
29
+ |---------|----------|---------------|
30
+ | 策略模式 | 接口 + 多个实现类 | 函数/callable传参 |
31
+ | 单例模式 | 双重检查锁 | 模块级变量/`__new__` |
32
+ | 迭代器模式 | Iterator接口 | `__iter__`/`__next__`/生成器 |
33
+ | 模板方法 | 抽象类 + 子类覆写 | 函数参数/hooks |
34
+ | 观察者模式 | Listener接口 | 信号/回调函数列表 |
35
+ | 装饰器模式 | 接口包装类 | `@decorator`语法 |
36
+ | 命令模式 | Command接口 + 实现 | callable对象/闭包 |
37
+
38
+ ---
39
+
40
+ ## 创建型模式
41
+
42
+ ### 1. 工厂方法模式 (Factory Method)
43
+
44
+ **问题描述**: 需要根据不同条件创建不同类型的对象,但调用方不应该依赖具体类。
45
+
46
+ **Python实现**:
47
+
48
+ ```python
49
+ from typing import Protocol, runtime_checkable
50
+ from dataclasses import dataclass
51
+
52
+ @runtime_checkable
53
+ class Notification(Protocol):
54
+ def send(self, message: str) -> bool: ...
55
+
56
+ @dataclass
57
+ class EmailNotification:
58
+ recipient: str
59
+
60
+ def send(self, message: str) -> bool:
61
+ print(f"Email to {self.recipient}: {message}")
62
+ return True
63
+
64
+ @dataclass
65
+ class SMSNotification:
66
+ phone: str
67
+
68
+ def send(self, message: str) -> bool:
69
+ print(f"SMS to {self.phone}: {message}")
70
+ return True
71
+
72
+ @dataclass
73
+ class SlackNotification:
74
+ channel: str
75
+
76
+ def send(self, message: str) -> bool:
77
+ print(f"Slack #{self.channel}: {message}")
78
+ return True
79
+
80
+ # Python惯用:用字典注册表替代工厂子类层次
81
+ _notification_registry: dict[str, type] = {
82
+ "email": EmailNotification,
83
+ "sms": SMSNotification,
84
+ "slack": SlackNotification,
85
+ }
86
+
87
+ def create_notification(channel: str, **kwargs) -> Notification:
88
+ """工厂函数:根据渠道类型创建通知对象"""
89
+ cls = _notification_registry.get(channel)
90
+ if cls is None:
91
+ raise ValueError(f"Unknown notification channel: {channel}")
92
+ return cls(**kwargs)
93
+
94
+ def register_notification(channel: str, cls: type) -> None:
95
+ """运行时注册新的通知类型,支持插件式扩展"""
96
+ _notification_registry[channel] = cls
97
+
98
+ # 使用
99
+ notif = create_notification("email", recipient="user@example.com")
100
+ notif.send("Your order has shipped")
101
+ ```
102
+
103
+ **使用场景**: 插件系统、多渠道通知、数据库驱动选择、序列化格式选择。
104
+
105
+ **注意事项**:
106
+ - 优先使用字典注册表而非类继承层次
107
+ - 工厂函数比工厂类更Pythonic
108
+ - 用`Protocol`定义产品接口而非抽象基类(除非需要默认实现)
109
+
110
+ ### 2. 抽象工厂模式 (Abstract Factory)
111
+
112
+ **问题描述**: 需要创建一组相关或相互依赖的对象族,且不指定它们的具体类。
113
+
114
+ **Python实现**:
115
+
116
+ ```python
117
+ from __future__ import annotations
118
+ from typing import Protocol
119
+ from dataclasses import dataclass, field
120
+
121
+ class Button(Protocol):
122
+ def render(self) -> str: ...
123
+
124
+ class TextInput(Protocol):
125
+ def render(self) -> str: ...
126
+
127
+ class Theme(Protocol):
128
+ def create_button(self, label: str) -> Button: ...
129
+ def create_text_input(self, placeholder: str) -> TextInput: ...
130
+
131
+ @dataclass
132
+ class MaterialButton:
133
+ label: str
134
+ def render(self) -> str:
135
+ return f'<button class="md-btn">{self.label}</button>'
136
+
137
+ @dataclass
138
+ class MaterialTextInput:
139
+ placeholder: str
140
+ def render(self) -> str:
141
+ return f'<input class="md-input" placeholder="{self.placeholder}"/>'
142
+
143
+ @dataclass
144
+ class AntDesignButton:
145
+ label: str
146
+ def render(self) -> str:
147
+ return f'<button class="ant-btn">{self.label}</button>'
148
+
149
+ @dataclass
150
+ class AntDesignTextInput:
151
+ placeholder: str
152
+ def render(self) -> str:
153
+ return f'<input class="ant-input" placeholder="{self.placeholder}"/>'
154
+
155
+ class MaterialTheme:
156
+ def create_button(self, label: str) -> Button:
157
+ return MaterialButton(label)
158
+ def create_text_input(self, placeholder: str) -> TextInput:
159
+ return MaterialTextInput(placeholder)
160
+
161
+ class AntDesignTheme:
162
+ def create_button(self, label: str) -> Button:
163
+ return AntDesignButton(label)
164
+ def create_text_input(self, placeholder: str) -> TextInput:
165
+ return AntDesignTextInput(placeholder)
166
+
167
+ def build_form(theme: Theme) -> list[str]:
168
+ """使用抽象工厂构建一致的UI表单"""
169
+ btn = theme.create_button("Submit")
170
+ inp = theme.create_text_input("Enter your name")
171
+ return [inp.render(), btn.render()]
172
+ ```
173
+
174
+ **使用场景**: UI主题系统、跨数据库ORM适配、多云基础设施抽象。
175
+
176
+ **注意事项**:
177
+ - Python中抽象工厂的使用频率低于Java,因为鸭子类型天然支持多态
178
+ - 考虑是否真的需要对象族一致性,否则简单工厂函数即可
179
+
180
+ ### 3. 建造者模式 (Builder)
181
+
182
+ **问题描述**: 构造复杂对象需要多个步骤,且不同表示可能需要相同的构造流程。
183
+
184
+ **Python实现**:
185
+
186
+ ```python
187
+ from __future__ import annotations
188
+ from dataclasses import dataclass, field
189
+ from typing import Self
190
+
191
+ @dataclass
192
+ class HTTPRequest:
193
+ method: str = "GET"
194
+ url: str = ""
195
+ headers: dict[str, str] = field(default_factory=dict)
196
+ query_params: dict[str, str] = field(default_factory=dict)
197
+ body: str | bytes | None = None
198
+ timeout: float = 30.0
199
+ retries: int = 0
200
+
201
+ class Builder:
202
+ """链式建造者,利用Python的Self类型实现流畅接口"""
203
+ def __init__(self) -> None:
204
+ self._method = "GET"
205
+ self._url = ""
206
+ self._headers: dict[str, str] = {}
207
+ self._query_params: dict[str, str] = {}
208
+ self._body: str | bytes | None = None
209
+ self._timeout: float = 30.0
210
+ self._retries: int = 0
211
+
212
+ def method(self, method: str) -> Self:
213
+ self._method = method
214
+ return self
215
+
216
+ def url(self, url: str) -> Self:
217
+ self._url = url
218
+ return self
219
+
220
+ def header(self, key: str, value: str) -> Self:
221
+ self._headers[key] = value
222
+ return self
223
+
224
+ def query(self, key: str, value: str) -> Self:
225
+ self._query_params[key] = value
226
+ return self
227
+
228
+ def body(self, body: str | bytes) -> Self:
229
+ self._body = body
230
+ return self
231
+
232
+ def timeout(self, seconds: float) -> Self:
233
+ self._timeout = seconds
234
+ return self
235
+
236
+ def retries(self, count: int) -> Self:
237
+ self._retries = count
238
+ return self
239
+
240
+ def build(self) -> HTTPRequest:
241
+ if not self._url:
242
+ raise ValueError("URL is required")
243
+ return HTTPRequest(
244
+ method=self._method,
245
+ url=self._url,
246
+ headers=self._headers,
247
+ query_params=self._query_params,
248
+ body=self._body,
249
+ timeout=self._timeout,
250
+ retries=self._retries,
251
+ )
252
+
253
+ # 使用
254
+ request = (
255
+ HTTPRequest.Builder()
256
+ .method("POST")
257
+ .url("https://api.example.com/orders")
258
+ .header("Content-Type", "application/json")
259
+ .header("Authorization", "Bearer token123")
260
+ .body('{"item": "widget", "qty": 3}')
261
+ .timeout(10.0)
262
+ .retries(3)
263
+ .build()
264
+ )
265
+ ```
266
+
267
+ **使用场景**: 复杂配置对象、SQL/查询构建器、HTTP请求构建、测试数据工厂。
268
+
269
+ **注意事项**:
270
+ - Python更常使用`dataclass` + 关键字参数替代简单的Builder
271
+ - 仅当构造过程有验证逻辑或步骤顺序约束时才值得用Builder
272
+ - `Self`类型(Python 3.11+)使链式调用具有正确的类型推导
273
+
274
+ ### 4. 单例模式 (Singleton)
275
+
276
+ **问题描述**: 确保一个类只有一个实例,并提供全局访问点。
277
+
278
+ **Python实现**:
279
+
280
+ ```python
281
+ # 方式一:模块级变量(最Pythonic,推荐)
282
+ # config.py
283
+ class _AppConfig:
284
+ def __init__(self) -> None:
285
+ self._settings: dict[str, object] = {}
286
+ self._loaded = False
287
+
288
+ def load(self, path: str) -> None:
289
+ # 从文件加载配置
290
+ self._loaded = True
291
+
292
+ def get(self, key: str, default: object = None) -> object:
293
+ return self._settings.get(key, default)
294
+
295
+ # 模块级单例:Python模块天然只初始化一次
296
+ app_config = _AppConfig()
297
+
298
+
299
+ # 方式二:__new__控制实例化(需要类级别单例时)
300
+ class DatabasePool:
301
+ _instance: "DatabasePool | None" = None
302
+
303
+ def __new__(cls) -> "DatabasePool":
304
+ if cls._instance is None:
305
+ cls._instance = super().__new__(cls)
306
+ cls._instance._initialized = False
307
+ return cls._instance
308
+
309
+ def __init__(self) -> None:
310
+ if self._initialized:
311
+ return
312
+ self._initialized = True
313
+ self._connections: list = []
314
+ self._max_size = 10
315
+
316
+ def get_connection(self):
317
+ # 从池中获取连接
318
+ pass
319
+
320
+
321
+ # 方式三:元类(适用于框架级控制)
322
+ class SingletonMeta(type):
323
+ _instances: dict[type, object] = {}
324
+
325
+ def __call__(cls, *args, **kwargs):
326
+ if cls not in cls._instances:
327
+ cls._instances[cls] = super().__call__(*args, **kwargs)
328
+ return cls._instances[cls]
329
+
330
+ class CacheManager(metaclass=SingletonMeta):
331
+ def __init__(self) -> None:
332
+ self._store: dict[str, object] = {}
333
+
334
+ def get(self, key: str) -> object | None:
335
+ return self._store.get(key)
336
+
337
+ def set(self, key: str, value: object) -> None:
338
+ self._store[key] = value
339
+ ```
340
+
341
+ **使用场景**: 配置管理、连接池、缓存管理器、日志管理。
342
+
343
+ **注意事项**:
344
+ - **优先使用模块级变量**,这是最Pythonic的单例实现
345
+ - 单例模式使测试困难(全局状态),考虑依赖注入替代
346
+ - 线程安全场景需加锁或使用`threading.Lock`
347
+ - 避免过度使用——大多数"需要单例"的场景实际上可以通过依赖注入解决
348
+
349
+ ### 5. 原型模式 (Prototype)
350
+
351
+ **问题描述**: 通过复制现有对象来创建新对象,避免重复的初始化开销。
352
+
353
+ **Python实现**:
354
+
355
+ ```python
356
+ import copy
357
+ from dataclasses import dataclass, field
358
+
359
+ @dataclass
360
+ class GameCharacter:
361
+ name: str
362
+ health: int
363
+ attack: int
364
+ defense: int
365
+ skills: list[str] = field(default_factory=list)
366
+ inventory: dict[str, int] = field(default_factory=dict)
367
+
368
+ def clone(self, **overrides) -> "GameCharacter":
369
+ """深拷贝并允许覆盖特定字段"""
370
+ cloned = copy.deepcopy(self)
371
+ for key, value in overrides.items():
372
+ if not hasattr(cloned, key):
373
+ raise AttributeError(f"GameCharacter has no attribute '{key}'")
374
+ setattr(cloned, key, value)
375
+ return cloned
376
+
377
+ # 预设原型注册表
378
+ _character_prototypes: dict[str, GameCharacter] = {
379
+ "warrior": GameCharacter(
380
+ name="Warrior",
381
+ health=150,
382
+ attack=30,
383
+ defense=25,
384
+ skills=["slash", "shield_bash"],
385
+ inventory={"health_potion": 3},
386
+ ),
387
+ "mage": GameCharacter(
388
+ name="Mage",
389
+ health=80,
390
+ attack=50,
391
+ defense=10,
392
+ skills=["fireball", "ice_shield"],
393
+ inventory={"mana_potion": 5},
394
+ ),
395
+ }
396
+
397
+ def create_character(archetype: str, name: str) -> GameCharacter:
398
+ proto = _character_prototypes.get(archetype)
399
+ if proto is None:
400
+ raise ValueError(f"Unknown archetype: {archetype}")
401
+ return proto.clone(name=name)
402
+
403
+ # 使用
404
+ hero = create_character("warrior", name="Arthas")
405
+ ```
406
+
407
+ **使用场景**: 配置模板、游戏对象预设、测试数据快速构造、文档模板。
408
+
409
+ **注意事项**:
410
+ - Python的`copy.deepcopy`是原型模式的天然支持
411
+ - 注意深拷贝与浅拷贝的区别,可变嵌套对象必须深拷贝
412
+ - `dataclass`的`replace`(Python 3.13+)提供了更安全的浅拷贝
413
+
414
+ ---
415
+
416
+ ## 结构型模式
417
+
418
+ ### 1. 适配器模式 (Adapter)
419
+
420
+ **问题描述**: 将一个接口转换为客户端期望的另一种接口,使不兼容的类可以协作。
421
+
422
+ **Python实现**:
423
+
424
+ ```python
425
+ from typing import Protocol
426
+ import json
427
+ import xml.etree.ElementTree as ET
428
+
429
+ class DataParser(Protocol):
430
+ def parse(self, raw: str) -> dict: ...
431
+
432
+ class JSONParser:
433
+ """原生支持的JSON解析器"""
434
+ def parse(self, raw: str) -> dict:
435
+ return json.loads(raw)
436
+
437
+ class LegacyXMLService:
438
+ """遗留系统,接口不符合DataParser协议"""
439
+ def read_xml(self, xml_string: str) -> ET.Element:
440
+ return ET.fromstring(xml_string)
441
+
442
+ def extract_data(self, element: ET.Element) -> dict[str, str]:
443
+ return {child.tag: (child.text or "") for child in element}
444
+
445
+ class XMLParserAdapter:
446
+ """适配器:将LegacyXMLService适配为DataParser接口"""
447
+ def __init__(self, legacy_service: LegacyXMLService | None = None) -> None:
448
+ self._service = legacy_service or LegacyXMLService()
449
+
450
+ def parse(self, raw: str) -> dict:
451
+ element = self._service.read_xml(raw)
452
+ return self._service.extract_data(element)
453
+
454
+ def process_data(parser: DataParser, raw: str) -> dict:
455
+ """客户端代码只依赖DataParser协议"""
456
+ return parser.parse(raw)
457
+
458
+ # 使用
459
+ json_result = process_data(JSONParser(), '{"name": "Alice"}')
460
+ xml_result = process_data(XMLParserAdapter(), "<root><name>Alice</name></root>")
461
+ ```
462
+
463
+ **使用场景**: 第三方库集成、遗留系统封装、API版本适配、多数据源统一接口。
464
+
465
+ **注意事项**:
466
+ - Python的鸭子类型使适配更轻量——只需实现相同的方法签名
467
+ - 优先使用组合(持有被适配对象引用)而非继承
468
+
469
+ ### 2. 装饰器模式 (Decorator)
470
+
471
+ **问题描述**: 动态地给对象添加额外职责,比子类化更灵活。
472
+
473
+ **Python实现**:
474
+
475
+ ```python
476
+ import functools
477
+ import time
478
+ import logging
479
+ from typing import Callable, ParamSpec, TypeVar
480
+
481
+ P = ParamSpec("P")
482
+ R = TypeVar("R")
483
+
484
+ logger = logging.getLogger(__name__)
485
+
486
+ def retry(max_attempts: int = 3, delay: float = 1.0):
487
+ """重试装饰器:失败时自动重试"""
488
+ def decorator(func: Callable[P, R]) -> Callable[P, R]:
489
+ @functools.wraps(func)
490
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
491
+ last_exception: Exception | None = None
492
+ for attempt in range(1, max_attempts + 1):
493
+ try:
494
+ return func(*args, **kwargs)
495
+ except Exception as exc:
496
+ last_exception = exc
497
+ logger.warning(
498
+ "Attempt %d/%d failed for %s: %s",
499
+ attempt, max_attempts, func.__name__, exc,
500
+ )
501
+ if attempt < max_attempts:
502
+ time.sleep(delay * attempt) # 指数退避
503
+ raise last_exception # type: ignore[misc]
504
+ return wrapper
505
+ return decorator
506
+
507
+ def timing(func: Callable[P, R]) -> Callable[P, R]:
508
+ """计时装饰器:记录函数执行时间"""
509
+ @functools.wraps(func)
510
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
511
+ start = time.perf_counter()
512
+ try:
513
+ result = func(*args, **kwargs)
514
+ return result
515
+ finally:
516
+ elapsed = time.perf_counter() - start
517
+ logger.info("%s took %.3fs", func.__name__, elapsed)
518
+ return wrapper
519
+
520
+ def cache_result(ttl_seconds: float = 60.0):
521
+ """带TTL的缓存装饰器"""
522
+ def decorator(func: Callable[P, R]) -> Callable[P, R]:
523
+ _cache: dict[tuple, tuple[float, R]] = {}
524
+
525
+ @functools.wraps(func)
526
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
527
+ key = (args, tuple(sorted(kwargs.items())))
528
+ now = time.time()
529
+ if key in _cache:
530
+ cached_time, cached_value = _cache[key]
531
+ if now - cached_time < ttl_seconds:
532
+ return cached_value
533
+ result = func(*args, **kwargs)
534
+ _cache[key] = (now, result)
535
+ return result
536
+ return wrapper
537
+ return decorator
538
+
539
+ # 装饰器堆叠:从下往上应用
540
+ @timing
541
+ @retry(max_attempts=3, delay=0.5)
542
+ def fetch_user_data(user_id: int) -> dict:
543
+ """模拟获取用户数据的远程调用"""
544
+ # 实际实现...
545
+ return {"id": user_id, "name": "Alice"}
546
+ ```
547
+
548
+ **使用场景**: 日志、缓存、认证检查、重试、限流、参数校验、事务管理。
549
+
550
+ **注意事项**:
551
+ - **必须使用`@functools.wraps`**保留原函数元信息(`__name__`, `__doc__`, `__module__`)
552
+ - 装饰器堆叠顺序很重要,从下到上执行(最内层先执行)
553
+ - 用`ParamSpec`和`TypeVar`保持正确的类型签名
554
+ - 对类方法使用装饰器时注意`self`参数的处理
555
+
556
+ ### 3. 代理模式 (Proxy)
557
+
558
+ **问题描述**: 控制对另一个对象的访问,提供额外的间接层。
559
+
560
+ **Python实现**:
561
+
562
+ ```python
563
+ from typing import Protocol
564
+ import time
565
+
566
+ class ImageLoader(Protocol):
567
+ def load(self) -> bytes: ...
568
+ @property
569
+ def filename(self) -> str: ...
570
+
571
+ class RealImageLoader:
572
+ """真实的图片加载器,可能涉及昂贵的IO操作"""
573
+ def __init__(self, filename: str) -> None:
574
+ self._filename = filename
575
+ self._data: bytes | None = None
576
+
577
+ @property
578
+ def filename(self) -> str:
579
+ return self._filename
580
+
581
+ def load(self) -> bytes:
582
+ if self._data is None:
583
+ print(f"Loading image from disk: {self._filename}")
584
+ time.sleep(0.5) # 模拟IO延迟
585
+ self._data = b"<image-binary-data>"
586
+ return self._data
587
+
588
+ class LazyImageProxy:
589
+ """延迟加载代理:直到真正需要数据时才加载"""
590
+ def __init__(self, filename: str) -> None:
591
+ self._filename = filename
592
+ self._real_loader: RealImageLoader | None = None
593
+
594
+ @property
595
+ def filename(self) -> str:
596
+ return self._filename
597
+
598
+ def _ensure_loaded(self) -> RealImageLoader:
599
+ if self._real_loader is None:
600
+ self._real_loader = RealImageLoader(self._filename)
601
+ return self._real_loader
602
+
603
+ def load(self) -> bytes:
604
+ return self._ensure_loaded().load()
605
+
606
+ class AccessControlProxy:
607
+ """访问控制代理:检查权限后转发请求"""
608
+ def __init__(self, loader: ImageLoader, allowed_roles: set[str]) -> None:
609
+ self._loader = loader
610
+ self._allowed_roles = allowed_roles
611
+
612
+ @property
613
+ def filename(self) -> str:
614
+ return self._loader.filename
615
+
616
+ def load(self, *, role: str = "viewer") -> bytes:
617
+ if role not in self._allowed_roles:
618
+ raise PermissionError(
619
+ f"Role '{role}' not allowed to load {self.filename}"
620
+ )
621
+ return self._loader.load()
622
+ ```
623
+
624
+ **使用场景**: 延迟加载、访问控制、缓存代理、远程代理(RPC)、日志代理。
625
+
626
+ **注意事项**:
627
+ - Python中`__getattr__`可以实现透明代理,自动转发所有未定义的属性访问
628
+ - 与装饰器模式的区别:代理控制访问,装饰器增强功能
629
+
630
+ ### 4. 外观模式 (Facade)
631
+
632
+ **问题描述**: 为复杂子系统提供简化的统一接口。
633
+
634
+ **Python实现**:
635
+
636
+ ```python
637
+ from dataclasses import dataclass
638
+
639
+ # 复杂的子系统组件
640
+ class InventoryService:
641
+ def check_stock(self, product_id: str) -> int:
642
+ return 42 # 模拟库存查询
643
+
644
+ def reserve(self, product_id: str, quantity: int) -> str:
645
+ return f"RESERVE-{product_id}-{quantity}"
646
+
647
+ class PaymentService:
648
+ def charge(self, amount: float, payment_method: str) -> str:
649
+ return f"TXN-{amount}"
650
+
651
+ def refund(self, transaction_id: str) -> bool:
652
+ return True
653
+
654
+ class ShippingService:
655
+ def calculate_cost(self, weight: float, destination: str) -> float:
656
+ return weight * 2.5
657
+
658
+ def create_shipment(self, order_id: str, destination: str) -> str:
659
+ return f"SHIP-{order_id}"
660
+
661
+ class NotificationService:
662
+ def send_email(self, to: str, subject: str, body: str) -> None:
663
+ pass
664
+
665
+ def send_sms(self, phone: str, message: str) -> None:
666
+ pass
667
+
668
+ @dataclass
669
+ class OrderResult:
670
+ order_id: str
671
+ transaction_id: str
672
+ shipment_id: str
673
+ total_cost: float
674
+
675
+ class OrderFacade:
676
+ """订单外观:将复杂的多步骤订单流程封装为简单接口"""
677
+ def __init__(
678
+ self,
679
+ inventory: InventoryService | None = None,
680
+ payment: PaymentService | None = None,
681
+ shipping: ShippingService | None = None,
682
+ notification: NotificationService | None = None,
683
+ ) -> None:
684
+ self._inventory = inventory or InventoryService()
685
+ self._payment = payment or PaymentService()
686
+ self._shipping = shipping or ShippingService()
687
+ self._notification = notification or NotificationService()
688
+
689
+ def place_order(
690
+ self,
691
+ product_id: str,
692
+ quantity: int,
693
+ payment_method: str,
694
+ destination: str,
695
+ customer_email: str,
696
+ ) -> OrderResult:
697
+ """一步完成下单:检查库存->预留->计费->发货->通知"""
698
+ stock = self._inventory.check_stock(product_id)
699
+ if stock < quantity:
700
+ raise ValueError(f"Insufficient stock: {stock} < {quantity}")
701
+
702
+ reservation = self._inventory.reserve(product_id, quantity)
703
+ shipping_cost = self._shipping.calculate_cost(quantity * 0.5, destination)
704
+ total = quantity * 19.99 + shipping_cost
705
+ txn_id = self._payment.charge(total, payment_method)
706
+ ship_id = self._shipping.create_shipment(reservation, destination)
707
+ self._notification.send_email(
708
+ customer_email, "Order Confirmed", f"Shipment: {ship_id}"
709
+ )
710
+ return OrderResult(
711
+ order_id=reservation,
712
+ transaction_id=txn_id,
713
+ shipment_id=ship_id,
714
+ total_cost=total,
715
+ )
716
+ ```
717
+
718
+ **使用场景**: 复杂API简化、子系统封装、微服务聚合层、SDK封装。
719
+
720
+ **注意事项**:
721
+ - 外观不应成为"上帝对象"——只封装常见工作流,不代替子系统
722
+ - 允许客户端在需要时绕过外观直接使用子系统
723
+
724
+ ### 5. 组合模式 (Composite)
725
+
726
+ **问题描述**: 将对象组合成树形结构以表示"部分-整体"层次,使客户端对单个对象和组合对象的使用具有一致性。
727
+
728
+ **Python实现**:
729
+
730
+ ```python
731
+ from __future__ import annotations
732
+ from dataclasses import dataclass, field
733
+
734
+ @dataclass
735
+ class FileSystemItem:
736
+ name: str
737
+
738
+ def size(self) -> int:
739
+ raise NotImplementedError
740
+
741
+ def display(self, indent: int = 0) -> str:
742
+ raise NotImplementedError
743
+
744
+ @dataclass
745
+ class File(FileSystemItem):
746
+ _size: int = 0
747
+
748
+ def size(self) -> int:
749
+ return self._size
750
+
751
+ def display(self, indent: int = 0) -> str:
752
+ prefix = " " * indent
753
+ return f"{prefix}{self.name} ({self._size}B)"
754
+
755
+ @dataclass
756
+ class Directory(FileSystemItem):
757
+ children: list[FileSystemItem] = field(default_factory=list)
758
+
759
+ def add(self, item: FileSystemItem) -> None:
760
+ self.children.append(item)
761
+
762
+ def remove(self, name: str) -> None:
763
+ self.children = [c for c in self.children if c.name != name]
764
+
765
+ def size(self) -> int:
766
+ return sum(child.size() for child in self.children)
767
+
768
+ def display(self, indent: int = 0) -> str:
769
+ prefix = " " * indent
770
+ lines = [f"{prefix}{self.name}/ ({self.size()}B)"]
771
+ for child in self.children:
772
+ lines.append(child.display(indent + 1))
773
+ return "\n".join(lines)
774
+
775
+ # 使用
776
+ root = Directory("project")
777
+ src = Directory("src")
778
+ src.add(File("main.py", 1200))
779
+ src.add(File("utils.py", 800))
780
+ root.add(src)
781
+ root.add(File("README.md", 500))
782
+ print(root.display())
783
+ # project/ (2500B)
784
+ # src/ (2000B)
785
+ # main.py (1200B)
786
+ # utils.py (800B)
787
+ # README.md (500B)
788
+ ```
789
+
790
+ **使用场景**: 文件系统、UI组件树、组织架构、菜单系统、权限树。
791
+
792
+ **注意事项**:
793
+ - 注意避免循环引用(目录不应包含自己的祖先)
794
+ - 递归操作注意深度限制(`sys.setrecursionlimit`)
795
+
796
+ ### 6. 享元模式 (Flyweight)
797
+
798
+ **问题描述**: 通过共享细粒度对象来减少内存使用。
799
+
800
+ **Python实现**:
801
+
802
+ ```python
803
+ import weakref
804
+ from dataclasses import dataclass
805
+
806
+ @dataclass(frozen=True)
807
+ class TextStyle:
808
+ """不可变的文本样式——内在状态,可共享"""
809
+ font_family: str
810
+ font_size: int
811
+ bold: bool
812
+ italic: bool
813
+ color: str
814
+
815
+ class TextStyleFactory:
816
+ """享元工厂:相同样式只创建一个实例"""
817
+ _cache: dict[tuple, TextStyle] = {}
818
+
819
+ @classmethod
820
+ def get_style(
821
+ cls,
822
+ font_family: str = "Arial",
823
+ font_size: int = 12,
824
+ bold: bool = False,
825
+ italic: bool = False,
826
+ color: str = "#000000",
827
+ ) -> TextStyle:
828
+ key = (font_family, font_size, bold, italic, color)
829
+ if key not in cls._cache:
830
+ cls._cache[key] = TextStyle(
831
+ font_family=font_family,
832
+ font_size=font_size,
833
+ bold=bold,
834
+ italic=italic,
835
+ color=color,
836
+ )
837
+ return cls._cache[key]
838
+
839
+ @classmethod
840
+ def cache_size(cls) -> int:
841
+ return len(cls._cache)
842
+
843
+ @dataclass
844
+ class TextCharacter:
845
+ """单个字符——外在状态(位置)+ 共享的内在状态(样式)"""
846
+ char: str
847
+ x: int
848
+ y: int
849
+ style: TextStyle
850
+
851
+ # 使用:100万个字符只需少量样式对象
852
+ body_style = TextStyleFactory.get_style("Arial", 12, False, False, "#333")
853
+ bold_style = TextStyleFactory.get_style("Arial", 12, True, False, "#333")
854
+ characters = [TextCharacter("H", 0, 0, bold_style)]
855
+ characters.extend(TextCharacter(c, i * 8, 0, body_style) for i, c in enumerate("ello World", 1))
856
+ # 尽管有11个字符对象,只创建了2个样式对象
857
+ ```
858
+
859
+ **使用场景**: 文本渲染、地图瓦片、粒子系统、字符串驻留。
860
+
861
+ **注意事项**:
862
+ - Python的`str`和小整数已使用享元(字符串驻留、整数缓存)
863
+ - 用`frozen=True`的`dataclass`或`__slots__`进一步优化
864
+ - `weakref.WeakValueDictionary`可让不再引用的享元被GC回收
865
+
866
+ ---
867
+
868
+ ## 行为型模式
869
+
870
+ ### 1. 策略模式 (Strategy)
871
+
872
+ **问题描述**: 定义一族算法,将每个算法封装起来,使它们可以互相替换。
873
+
874
+ **Python实现**:
875
+
876
+ ```python
877
+ from typing import Callable
878
+ from dataclasses import dataclass
879
+
880
+ # Python惯用:策略就是函数
881
+ PricingStrategy = Callable[[float, int], float]
882
+
883
+ def regular_pricing(unit_price: float, quantity: int) -> float:
884
+ """标准定价"""
885
+ return unit_price * quantity
886
+
887
+ def bulk_pricing(unit_price: float, quantity: int) -> float:
888
+ """批量折扣:10件以上打8折"""
889
+ total = unit_price * quantity
890
+ if quantity > 10:
891
+ total *= 0.8
892
+ return total
893
+
894
+ def vip_pricing(unit_price: float, quantity: int) -> float:
895
+ """VIP定价:全场7折"""
896
+ return unit_price * quantity * 0.7
897
+
898
+ def seasonal_pricing(discount: float = 0.85) -> PricingStrategy:
899
+ """季节性定价:闭包捕获折扣率"""
900
+ def strategy(unit_price: float, quantity: int) -> float:
901
+ return unit_price * quantity * discount
902
+ return strategy
903
+
904
+ @dataclass
905
+ class Order:
906
+ product: str
907
+ unit_price: float
908
+ quantity: int
909
+ pricing: PricingStrategy = regular_pricing # 默认策略
910
+
911
+ def total(self) -> float:
912
+ return self.pricing(self.unit_price, self.quantity)
913
+
914
+ # 使用:策略作为参数传入
915
+ order_a = Order("Widget", 10.0, 5, pricing=regular_pricing)
916
+ order_b = Order("Widget", 10.0, 20, pricing=bulk_pricing)
917
+ order_c = Order("Widget", 10.0, 5, pricing=seasonal_pricing(0.9))
918
+ print(order_a.total()) # 50.0
919
+ print(order_b.total()) # 160.0
920
+ print(order_c.total()) # 45.0
921
+ ```
922
+
923
+ **使用场景**: 定价策略、排序算法选择、验证规则、序列化格式、压缩算法。
924
+
925
+ **注意事项**:
926
+ - Python中策略模式的最佳实现就是传递函数,无需类层次
927
+ - 需要携带状态的策略可用闭包或callable类
928
+ - 避免为了"模式"而创建不必要的Strategy接口和实现类
929
+
930
+ ### 2. 观察者模式 (Observer)
931
+
932
+ **问题描述**: 定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者都得到通知。
933
+
934
+ **Python实现**:
935
+
936
+ ```python
937
+ from __future__ import annotations
938
+ from typing import Callable, Any
939
+ from dataclasses import dataclass, field
940
+ from collections import defaultdict
941
+ import weakref
942
+
943
+ # 事件类型标识
944
+ type EventHandler = Callable[[str, dict[str, Any]], None]
945
+
946
+ class EventBus:
947
+ """轻量级事件总线:基于回调函数的观察者模式"""
948
+ def __init__(self) -> None:
949
+ self._handlers: dict[str, list[EventHandler]] = defaultdict(list)
950
+
951
+ def subscribe(self, event: str, handler: EventHandler) -> Callable[[], None]:
952
+ """订阅事件,返回取消订阅的函数"""
953
+ self._handlers[event].append(handler)
954
+ def unsubscribe() -> None:
955
+ self._handlers[event].remove(handler)
956
+ return unsubscribe
957
+
958
+ def publish(self, event: str, data: dict[str, Any] | None = None) -> None:
959
+ """发布事件,通知所有订阅者"""
960
+ for handler in self._handlers.get(event, []):
961
+ handler(event, data or {})
962
+
963
+ def clear(self, event: str | None = None) -> None:
964
+ if event:
965
+ self._handlers.pop(event, None)
966
+ else:
967
+ self._handlers.clear()
968
+
969
+ # 使用
970
+ bus = EventBus()
971
+
972
+ def on_user_created(event: str, data: dict[str, Any]) -> None:
973
+ print(f"Send welcome email to {data['email']}")
974
+
975
+ def on_user_created_audit(event: str, data: dict[str, Any]) -> None:
976
+ print(f"Audit log: user {data['user_id']} created")
977
+
978
+ unsub1 = bus.subscribe("user.created", on_user_created)
979
+ unsub2 = bus.subscribe("user.created", on_user_created_audit)
980
+
981
+ bus.publish("user.created", {"user_id": 42, "email": "new@example.com"})
982
+ # Send welcome email to new@example.com
983
+ # Audit log: user 42 created
984
+
985
+ unsub1() # 取消welcome邮件的订阅
986
+ ```
987
+
988
+ **使用场景**: UI事件处理、领域事件、消息队列抽象、插件系统、数据绑定。
989
+
990
+ **注意事项**:
991
+ - 注意内存泄漏:长生命周期的事件总线可能持有已不需要的handler引用
992
+ - 考虑使用`weakref`避免循环引用
993
+ - 异步场景使用`asyncio.Event`或异步事件总线
994
+
995
+ ### 3. 命令模式 (Command)
996
+
997
+ **问题描述**: 将请求封装为对象,支持撤销、队列和日志记录。
998
+
999
+ **Python实现**:
1000
+
1001
+ ```python
1002
+ from __future__ import annotations
1003
+ from typing import Protocol
1004
+ from dataclasses import dataclass, field
1005
+
1006
+ class Command(Protocol):
1007
+ def execute(self) -> None: ...
1008
+ def undo(self) -> None: ...
1009
+ @property
1010
+ def description(self) -> str: ...
1011
+
1012
+ @dataclass
1013
+ class TextDocument:
1014
+ content: str = ""
1015
+
1016
+ def insert(self, position: int, text: str) -> None:
1017
+ self.content = self.content[:position] + text + self.content[position:]
1018
+
1019
+ def delete(self, position: int, length: int) -> str:
1020
+ deleted = self.content[position:position + length]
1021
+ self.content = self.content[:position] + self.content[position + length:]
1022
+ return deleted
1023
+
1024
+ @dataclass
1025
+ class InsertCommand:
1026
+ doc: TextDocument
1027
+ position: int
1028
+ text: str
1029
+
1030
+ @property
1031
+ def description(self) -> str:
1032
+ return f"Insert '{self.text}' at {self.position}"
1033
+
1034
+ def execute(self) -> None:
1035
+ self.doc.insert(self.position, self.text)
1036
+
1037
+ def undo(self) -> None:
1038
+ self.doc.delete(self.position, len(self.text))
1039
+
1040
+ @dataclass
1041
+ class DeleteCommand:
1042
+ doc: TextDocument
1043
+ position: int
1044
+ length: int
1045
+ _deleted_text: str = field(default="", init=False)
1046
+
1047
+ @property
1048
+ def description(self) -> str:
1049
+ return f"Delete {self.length} chars at {self.position}"
1050
+
1051
+ def execute(self) -> None:
1052
+ self._deleted_text = self.doc.delete(self.position, self.length)
1053
+
1054
+ def undo(self) -> None:
1055
+ self.doc.insert(self.position, self._deleted_text)
1056
+
1057
+ class CommandHistory:
1058
+ """命令历史管理器:支持撤销/重做"""
1059
+ def __init__(self) -> None:
1060
+ self._undo_stack: list[Command] = []
1061
+ self._redo_stack: list[Command] = []
1062
+
1063
+ def execute(self, command: Command) -> None:
1064
+ command.execute()
1065
+ self._undo_stack.append(command)
1066
+ self._redo_stack.clear() # 新命令清除重做栈
1067
+
1068
+ def undo(self) -> None:
1069
+ if not self._undo_stack:
1070
+ return
1071
+ cmd = self._undo_stack.pop()
1072
+ cmd.undo()
1073
+ self._redo_stack.append(cmd)
1074
+
1075
+ def redo(self) -> None:
1076
+ if not self._redo_stack:
1077
+ return
1078
+ cmd = self._redo_stack.pop()
1079
+ cmd.execute()
1080
+ self._undo_stack.append(cmd)
1081
+
1082
+ # 使用
1083
+ doc = TextDocument()
1084
+ history = CommandHistory()
1085
+ history.execute(InsertCommand(doc, 0, "Hello World"))
1086
+ history.execute(InsertCommand(doc, 5, ","))
1087
+ print(doc.content) # "Hello, World"
1088
+ history.undo()
1089
+ print(doc.content) # "Hello World"
1090
+ history.redo()
1091
+ print(doc.content) # "Hello, World"
1092
+ ```
1093
+
1094
+ **使用场景**: 文本编辑器撤销/重做、事务回滚、宏录制、任务队列、CLI命令执行。
1095
+
1096
+ **注意事项**:
1097
+ - 简单场景可以用callable替代Command类
1098
+ - 命令应捕获执行时的状态以支持可靠的undo
1099
+ - 注意命令与Memento模式结合以保存完整快照
1100
+
1101
+ ### 4. 状态机模式 (State Machine)
1102
+
1103
+ **问题描述**: 允许对象在其内部状态改变时改变其行为。
1104
+
1105
+ **Python实现**:
1106
+
1107
+ ```python
1108
+ from __future__ import annotations
1109
+ from enum import Enum, auto
1110
+ from dataclasses import dataclass, field
1111
+ from typing import Callable
1112
+
1113
+ class OrderStatus(Enum):
1114
+ PENDING = auto()
1115
+ PAID = auto()
1116
+ SHIPPED = auto()
1117
+ DELIVERED = auto()
1118
+ CANCELLED = auto()
1119
+
1120
+ # 状态转换定义:(当前状态, 事件) -> 下一个状态
1121
+ type TransitionKey = tuple[OrderStatus, str]
1122
+
1123
+ _TRANSITIONS: dict[TransitionKey, OrderStatus] = {
1124
+ (OrderStatus.PENDING, "pay"): OrderStatus.PAID,
1125
+ (OrderStatus.PENDING, "cancel"): OrderStatus.CANCELLED,
1126
+ (OrderStatus.PAID, "ship"): OrderStatus.SHIPPED,
1127
+ (OrderStatus.PAID, "cancel"): OrderStatus.CANCELLED,
1128
+ (OrderStatus.SHIPPED, "deliver"): OrderStatus.DELIVERED,
1129
+ }
1130
+
1131
+ type HookFn = Callable[["OrderStateMachine", str], None]
1132
+
1133
+ @dataclass
1134
+ class OrderStateMachine:
1135
+ order_id: str
1136
+ status: OrderStatus = OrderStatus.PENDING
1137
+ _on_transition: list[HookFn] = field(default_factory=list)
1138
+
1139
+ def add_hook(self, hook: HookFn) -> None:
1140
+ self._on_transition.append(hook)
1141
+
1142
+ def trigger(self, event: str) -> None:
1143
+ key = (self.status, event)
1144
+ next_status = _TRANSITIONS.get(key)
1145
+ if next_status is None:
1146
+ raise ValueError(
1147
+ f"Invalid transition: {self.status.name} + '{event}'"
1148
+ )
1149
+ old = self.status
1150
+ self.status = next_status
1151
+ for hook in self._on_transition:
1152
+ hook(self, f"{old.name} -> {next_status.name}")
1153
+
1154
+ @property
1155
+ def is_terminal(self) -> bool:
1156
+ return self.status in {OrderStatus.DELIVERED, OrderStatus.CANCELLED}
1157
+
1158
+ # 使用
1159
+ order = OrderStateMachine("ORD-001")
1160
+ order.add_hook(lambda sm, t: print(f"[{sm.order_id}] {t}"))
1161
+ order.trigger("pay") # [ORD-001] PENDING -> PAID
1162
+ order.trigger("ship") # [ORD-001] PAID -> SHIPPED
1163
+ order.trigger("deliver") # [ORD-001] SHIPPED -> DELIVERED
1164
+ ```
1165
+
1166
+ **使用场景**: 订单流程、工作流引擎、游戏AI、协议解析、审批流程。
1167
+
1168
+ **注意事项**:
1169
+ - 简单状态机用字典映射比类层次更清晰
1170
+ - 复杂场景考虑`transitions`库或`statemachine`库
1171
+ - 状态转换必须是显式的——不允许隐式跳跃
1172
+
1173
+ ### 5. 模板方法模式 (Template Method)
1174
+
1175
+ **问题描述**: 定义算法骨架,将某些步骤延迟到子类实现。
1176
+
1177
+ **Python实现**:
1178
+
1179
+ ```python
1180
+ from abc import ABC, abstractmethod
1181
+ from dataclasses import dataclass
1182
+ import time
1183
+
1184
+ @dataclass
1185
+ class ETLResult:
1186
+ records_extracted: int
1187
+ records_transformed: int
1188
+ records_loaded: int
1189
+ elapsed_seconds: float
1190
+
1191
+ class ETLPipeline(ABC):
1192
+ """ETL管道模板:固定的提取->转换->加载流程"""
1193
+ def run(self) -> ETLResult:
1194
+ start = time.time()
1195
+ raw = self.extract()
1196
+ transformed = self.transform(raw)
1197
+ count = self.load(transformed)
1198
+ elapsed = time.time() - start
1199
+ self.on_complete(count, elapsed) # 钩子方法
1200
+ return ETLResult(
1201
+ records_extracted=len(raw),
1202
+ records_transformed=len(transformed),
1203
+ records_loaded=count,
1204
+ elapsed_seconds=elapsed,
1205
+ )
1206
+
1207
+ @abstractmethod
1208
+ def extract(self) -> list[dict]: ...
1209
+
1210
+ @abstractmethod
1211
+ def transform(self, raw: list[dict]) -> list[dict]: ...
1212
+
1213
+ @abstractmethod
1214
+ def load(self, data: list[dict]) -> int: ...
1215
+
1216
+ def on_complete(self, count: int, elapsed: float) -> None:
1217
+ """钩子方法:子类可选覆写"""
1218
+ pass
1219
+
1220
+ class CSVToPostgresETL(ETLPipeline):
1221
+ def __init__(self, csv_path: str, table: str) -> None:
1222
+ self.csv_path = csv_path
1223
+ self.table = table
1224
+
1225
+ def extract(self) -> list[dict]:
1226
+ print(f"Reading CSV from {self.csv_path}")
1227
+ return [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
1228
+
1229
+ def transform(self, raw: list[dict]) -> list[dict]:
1230
+ return [
1231
+ {**row, "name": row["name"].strip().title()}
1232
+ for row in raw
1233
+ ]
1234
+
1235
+ def load(self, data: list[dict]) -> int:
1236
+ print(f"Inserting {len(data)} rows into {self.table}")
1237
+ return len(data)
1238
+
1239
+ def on_complete(self, count: int, elapsed: float) -> None:
1240
+ print(f"ETL complete: {count} records in {elapsed:.2f}s")
1241
+ ```
1242
+
1243
+ **使用场景**: ETL管道、测试框架(setUp/tearDown)、构建系统、报告生成器。
1244
+
1245
+ **注意事项**:
1246
+ - Python也可以用函数参数替代子类化实现模板方法
1247
+ - 钩子方法提供默认空实现,子类按需覆写
1248
+ - 避免模板方法嵌套太深——超过5个步骤考虑拆分
1249
+
1250
+ ### 6. 迭代器模式 (Iterator)
1251
+
1252
+ **问题描述**: 提供一种顺序访问聚合对象元素的方法,而不暴露其底层表示。
1253
+
1254
+ **Python实现**:
1255
+
1256
+ ```python
1257
+ from typing import Iterator, Generator
1258
+ from dataclasses import dataclass
1259
+
1260
+ @dataclass
1261
+ class Pagination:
1262
+ """分页迭代器:逐页获取远程数据"""
1263
+ base_url: str
1264
+ page_size: int = 20
1265
+
1266
+ def fetch_page(self, page: int) -> list[dict]:
1267
+ """模拟远程API分页请求"""
1268
+ if page > 5: # 模拟5页数据
1269
+ return []
1270
+ return [
1271
+ {"id": (page - 1) * self.page_size + i, "data": f"item-{i}"}
1272
+ for i in range(self.page_size)
1273
+ ]
1274
+
1275
+ def __iter__(self) -> Generator[dict, None, None]:
1276
+ """生成器实现:逐条yield,惰性加载每页"""
1277
+ page = 1
1278
+ while True:
1279
+ items = self.fetch_page(page)
1280
+ if not items:
1281
+ break
1282
+ yield from items
1283
+ page += 1
1284
+
1285
+ def chunked(iterable, size: int) -> Generator[list, None, None]:
1286
+ """通用分块迭代器"""
1287
+ chunk: list = []
1288
+ for item in iterable:
1289
+ chunk.append(item)
1290
+ if len(chunk) == size:
1291
+ yield chunk
1292
+ chunk = []
1293
+ if chunk:
1294
+ yield chunk
1295
+
1296
+ # 使用
1297
+ paginator = Pagination("https://api.example.com/items", page_size=20)
1298
+ for item in paginator:
1299
+ if item["id"] > 10:
1300
+ break
1301
+ print(item)
1302
+
1303
+ # 分块处理
1304
+ for batch in chunked(range(25), 10):
1305
+ print(f"Processing batch of {len(batch)} items")
1306
+ ```
1307
+
1308
+ **使用场景**: 分页API遍历、大文件逐行读取、数据库游标、树遍历、流式处理。
1309
+
1310
+ **注意事项**:
1311
+ - Python的生成器(`yield`)是迭代器的语法糖,优先使用
1312
+ - `yield from`委托子迭代器,避免手动循环
1313
+ - 迭代器是一次性的——需要多次遍历要重新创建或使用`itertools.tee`
1314
+
1315
+ ### 7. 责任链模式 (Chain of Responsibility)
1316
+
1317
+ **问题描述**: 将请求沿着处理者链传递,直到有一个处理者处理它。
1318
+
1319
+ **Python实现**:
1320
+
1321
+ ```python
1322
+ from __future__ import annotations
1323
+ from typing import Callable, Any
1324
+ from dataclasses import dataclass
1325
+
1326
+ # Python惯用:中间件/管道式责任链
1327
+ type Middleware = Callable[[dict[str, Any], Callable], dict[str, Any]]
1328
+
1329
+ def auth_middleware(request: dict[str, Any], next_handler: Callable) -> dict[str, Any]:
1330
+ token = request.get("headers", {}).get("Authorization")
1331
+ if not token:
1332
+ return {"status": 401, "body": "Unauthorized"}
1333
+ if not token.startswith("Bearer "):
1334
+ return {"status": 401, "body": "Invalid token format"}
1335
+ request["user"] = {"id": 1, "role": "admin"} # 模拟解析token
1336
+ return next_handler(request)
1337
+
1338
+ def rate_limit_middleware(request: dict[str, Any], next_handler: Callable) -> dict[str, Any]:
1339
+ client_ip = request.get("client_ip", "unknown")
1340
+ # 模拟限流检查
1341
+ if client_ip == "banned":
1342
+ return {"status": 429, "body": "Rate limit exceeded"}
1343
+ return next_handler(request)
1344
+
1345
+ def logging_middleware(request: dict[str, Any], next_handler: Callable) -> dict[str, Any]:
1346
+ print(f"[LOG] {request.get('method', 'GET')} {request.get('path', '/')}")
1347
+ response = next_handler(request)
1348
+ print(f"[LOG] Response: {response.get('status', 200)}")
1349
+ return response
1350
+
1351
+ class MiddlewarePipeline:
1352
+ """中间件管道:按顺序组装处理链"""
1353
+ def __init__(self) -> None:
1354
+ self._middlewares: list[Middleware] = []
1355
+
1356
+ def use(self, middleware: Middleware) -> "MiddlewarePipeline":
1357
+ self._middlewares.append(middleware)
1358
+ return self
1359
+
1360
+ def handle(self, request: dict[str, Any], final: Callable) -> dict[str, Any]:
1361
+ """构建责任链并执行"""
1362
+ handler = final
1363
+ for mw in reversed(self._middlewares):
1364
+ prev_handler = handler
1365
+ handler = lambda req, _mw=mw, _next=prev_handler: _mw(req, _next)
1366
+ return handler(request)
1367
+
1368
+ # 使用
1369
+ pipeline = MiddlewarePipeline()
1370
+ pipeline.use(logging_middleware).use(rate_limit_middleware).use(auth_middleware)
1371
+
1372
+ def handle_request(request: dict[str, Any]) -> dict[str, Any]:
1373
+ return {"status": 200, "body": f"Hello, user {request['user']['id']}"}
1374
+
1375
+ response = pipeline.handle(
1376
+ {"method": "GET", "path": "/api/data", "headers": {"Authorization": "Bearer abc123"}},
1377
+ handle_request,
1378
+ )
1379
+ ```
1380
+
1381
+ **使用场景**: HTTP中间件、日志处理链、审批流程、输入验证管道、异常处理层。
1382
+
1383
+ **注意事项**:
1384
+ - Python中间件模式(WSGI/ASGI)就是责任链的典型应用
1385
+ - 注意闭包变量捕获问题(使用默认参数绑定)
1386
+ - 链中的每个处理者应该只关注自己的职责
1387
+
1388
+ ---
1389
+
1390
+ ## Python特有模式
1391
+
1392
+ ### 1. Mixin模式
1393
+
1394
+ **问题描述**: 通过多重继承为类添加可复用的功能片段,而不建立is-a关系。
1395
+
1396
+ **Python实现**:
1397
+
1398
+ ```python
1399
+ import json
1400
+ import time
1401
+ from typing import Any
1402
+
1403
+ class SerializableMixin:
1404
+ """JSON序列化能力"""
1405
+ def to_json(self) -> str:
1406
+ data = {}
1407
+ for key, value in self.__dict__.items():
1408
+ if not key.startswith("_"):
1409
+ data[key] = value
1410
+ return json.dumps(data, default=str, ensure_ascii=False)
1411
+
1412
+ @classmethod
1413
+ def from_json(cls, json_str: str) -> "SerializableMixin":
1414
+ data = json.loads(json_str)
1415
+ instance = cls.__new__(cls)
1416
+ instance.__dict__.update(data)
1417
+ return instance
1418
+
1419
+ class TimestampMixin:
1420
+ """自动时间戳追踪"""
1421
+ def __init_subclass__(cls, **kwargs: Any) -> None:
1422
+ super().__init_subclass__(**kwargs)
1423
+ original_init = cls.__init__
1424
+
1425
+ def new_init(self: Any, *args: Any, **kw: Any) -> None:
1426
+ original_init(self, *args, **kw)
1427
+ self.created_at = time.time()
1428
+ self.updated_at = time.time()
1429
+
1430
+ cls.__init__ = new_init # type: ignore[attr-defined]
1431
+
1432
+ def touch(self) -> None:
1433
+ self.updated_at = time.time()
1434
+
1435
+ class ValidatableMixin:
1436
+ """声明式字段验证"""
1437
+ _validators: dict[str, list] = {}
1438
+
1439
+ def validate(self) -> list[str]:
1440
+ errors: list[str] = []
1441
+ for field_name, validators in self._validators.items():
1442
+ value = getattr(self, field_name, None)
1443
+ for validator_fn, msg in validators:
1444
+ if not validator_fn(value):
1445
+ errors.append(f"{field_name}: {msg}")
1446
+ return errors
1447
+
1448
+ class User(SerializableMixin, TimestampMixin, ValidatableMixin):
1449
+ _validators = {
1450
+ "name": [
1451
+ (lambda v: v and len(v) >= 2, "Name must be at least 2 characters"),
1452
+ ],
1453
+ "email": [
1454
+ (lambda v: v and "@" in v, "Invalid email format"),
1455
+ ],
1456
+ }
1457
+
1458
+ def __init__(self, name: str, email: str) -> None:
1459
+ self.name = name
1460
+ self.email = email
1461
+
1462
+ # 使用
1463
+ user = User("Alice", "alice@example.com")
1464
+ print(user.to_json()) # 序列化
1465
+ print(user.created_at) # 时间戳
1466
+ print(user.validate()) # 验证 -> []
1467
+ ```
1468
+
1469
+ **使用场景**: ORM模型增强、API序列化、审计日志、权限控制、缓存能力注入。
1470
+
1471
+ **注意事项**:
1472
+ - Mixin类不应独立实例化,且不应有`__init__`(除非通过`__init_subclass__`)
1473
+ - MRO(方法解析顺序)从左到右——将最具体的Mixin放在最左边
1474
+ - 避免Mixin之间有方法名冲突
1475
+
1476
+ ### 2. 描述符模式 (Descriptor)
1477
+
1478
+ **问题描述**: 通过定义`__get__`、`__set__`、`__delete__`方法控制属性访问行为。
1479
+
1480
+ **Python实现**:
1481
+
1482
+ ```python
1483
+ from typing import Any, Callable
1484
+
1485
+ class Validated:
1486
+ """通用验证描述符"""
1487
+ def __init__(self, validator: Callable[[Any], bool], error_msg: str) -> None:
1488
+ self.validator = validator
1489
+ self.error_msg = error_msg
1490
+ self.attr_name = ""
1491
+
1492
+ def __set_name__(self, owner: type, name: str) -> None:
1493
+ self.attr_name = name
1494
+ self.storage_name = f"_desc_{name}"
1495
+
1496
+ def __get__(self, obj: Any, objtype: type | None = None) -> Any:
1497
+ if obj is None:
1498
+ return self
1499
+ return getattr(obj, self.storage_name, None)
1500
+
1501
+ def __set__(self, obj: Any, value: Any) -> None:
1502
+ if not self.validator(value):
1503
+ raise ValueError(f"{self.attr_name}: {self.error_msg} (got {value!r})")
1504
+ setattr(obj, self.storage_name, value)
1505
+
1506
+ class PositiveNumber(Validated):
1507
+ def __init__(self, error_msg: str = "must be positive") -> None:
1508
+ super().__init__(lambda v: isinstance(v, (int, float)) and v > 0, error_msg)
1509
+
1510
+ class NonEmptyString(Validated):
1511
+ def __init__(self, max_length: int = 255) -> None:
1512
+ super().__init__(
1513
+ lambda v: isinstance(v, str) and 0 < len(v) <= max_length,
1514
+ f"must be non-empty string (max {max_length} chars)",
1515
+ )
1516
+
1517
+ class InRange(Validated):
1518
+ def __init__(self, min_val: float, max_val: float) -> None:
1519
+ super().__init__(
1520
+ lambda v: isinstance(v, (int, float)) and min_val <= v <= max_val,
1521
+ f"must be between {min_val} and {max_val}",
1522
+ )
1523
+
1524
+ class Product:
1525
+ name = NonEmptyString(max_length=100)
1526
+ price = PositiveNumber()
1527
+ rating = InRange(0.0, 5.0)
1528
+
1529
+ def __init__(self, name: str, price: float, rating: float) -> None:
1530
+ self.name = name
1531
+ self.price = price
1532
+ self.rating = rating
1533
+
1534
+ # 使用
1535
+ p = Product("Widget", 9.99, 4.5) # OK
1536
+ # Product("", 9.99, 4.5) # ValueError: name: must be non-empty string
1537
+ # Product("Widget", -1, 4.5) # ValueError: price: must be positive
1538
+ ```
1539
+
1540
+ **使用场景**: ORM字段定义、表单验证、属性缓存(`cached_property`就是描述符)、类型强制。
1541
+
1542
+ **注意事项**:
1543
+ - `__set_name__`(Python 3.6+)自动获取属性名,不再需要手动传入
1544
+ - 描述符存储值时避免用实例`__dict__`的同名键(会遮蔽描述符)
1545
+ - `property`本身就是描述符的语法糖
1546
+
1547
+ ### 3. 元类模式 (Metaclass)
1548
+
1549
+ **问题描述**: 控制类的创建过程,实现类级别的约束和自动化。
1550
+
1551
+ **Python实现**:
1552
+
1553
+ ```python
1554
+ from typing import Any
1555
+
1556
+ class PluginMeta(type):
1557
+ """插件注册元类:所有子类自动注册到注册表"""
1558
+ _registry: dict[str, type] = {}
1559
+
1560
+ def __new__(
1561
+ mcs,
1562
+ name: str,
1563
+ bases: tuple[type, ...],
1564
+ namespace: dict[str, Any],
1565
+ **kwargs: Any,
1566
+ ) -> "PluginMeta":
1567
+ cls = super().__new__(mcs, name, bases, namespace)
1568
+ # 不注册基类本身
1569
+ if bases:
1570
+ plugin_name = getattr(cls, "plugin_name", name.lower())
1571
+ mcs._registry[plugin_name] = cls
1572
+ return cls
1573
+
1574
+ @classmethod
1575
+ def get_plugin(mcs, name: str) -> type | None:
1576
+ return mcs._registry.get(name)
1577
+
1578
+ @classmethod
1579
+ def list_plugins(mcs) -> list[str]:
1580
+ return list(mcs._registry.keys())
1581
+
1582
+ class Plugin(metaclass=PluginMeta):
1583
+ """插件基类"""
1584
+ plugin_name: str
1585
+
1586
+ def execute(self, data: dict) -> dict:
1587
+ raise NotImplementedError
1588
+
1589
+ class JSONExporter(Plugin):
1590
+ plugin_name = "json_exporter"
1591
+ def execute(self, data: dict) -> dict:
1592
+ return {"format": "json", "output": str(data)}
1593
+
1594
+ class CSVExporter(Plugin):
1595
+ plugin_name = "csv_exporter"
1596
+ def execute(self, data: dict) -> dict:
1597
+ header = ",".join(data.keys())
1598
+ values = ",".join(str(v) for v in data.values())
1599
+ return {"format": "csv", "output": f"{header}\n{values}"}
1600
+
1601
+ # 使用:自动发现所有已注册的插件
1602
+ print(PluginMeta.list_plugins()) # ['json_exporter', 'csv_exporter']
1603
+ plugin_cls = PluginMeta.get_plugin("json_exporter")
1604
+ if plugin_cls:
1605
+ result = plugin_cls().execute({"name": "Alice", "age": 30})
1606
+ ```
1607
+
1608
+ **使用场景**: 插件系统、ORM模型注册、API路由自动收集、接口合约强制。
1609
+
1610
+ **注意事项**:
1611
+ - 元类是Python最强大的工具,也最容易滥用
1612
+ - **优先考虑`__init_subclass__`**(Python 3.6+),它能覆盖大部分元类场景且更简单
1613
+ - 避免多层元类继承——极难调试
1614
+ - Django ORM和SQLAlchemy大量使用元类,但业务代码很少需要
1615
+
1616
+ ### 4. 上下文管理器协议 (Context Manager)
1617
+
1618
+ **问题描述**: 确保资源的正确获取和释放,即使发生异常。
1619
+
1620
+ **Python实现**:
1621
+
1622
+ ```python
1623
+ from __future__ import annotations
1624
+ import time
1625
+ from contextlib import contextmanager
1626
+ from typing import Generator, Any
1627
+ from dataclasses import dataclass, field
1628
+
1629
+ # 方式一:类实现
1630
+ @dataclass
1631
+ class DatabaseTransaction:
1632
+ """数据库事务上下文管理器"""
1633
+ connection: Any
1634
+ _savepoint: str | None = field(default=None, init=False)
1635
+
1636
+ def __enter__(self) -> "DatabaseTransaction":
1637
+ self._savepoint = f"sp_{id(self)}"
1638
+ print(f"BEGIN TRANSACTION (savepoint: {self._savepoint})")
1639
+ return self
1640
+
1641
+ def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
1642
+ if exc_type is not None:
1643
+ print(f"ROLLBACK to {self._savepoint}: {exc_val}")
1644
+ # 返回True表示异常已处理,不再传播
1645
+ return False
1646
+ print("COMMIT")
1647
+ return False
1648
+
1649
+ def execute(self, sql: str) -> list[dict]:
1650
+ print(f" EXEC: {sql}")
1651
+ return []
1652
+
1653
+ # 方式二:生成器实现(更简洁)
1654
+ @contextmanager
1655
+ def timer(label: str) -> Generator[dict[str, float], None, None]:
1656
+ """计时上下文管理器"""
1657
+ result: dict[str, float] = {}
1658
+ start = time.perf_counter()
1659
+ try:
1660
+ yield result
1661
+ finally:
1662
+ result["elapsed"] = time.perf_counter() - start
1663
+ print(f"[{label}] {result['elapsed']:.4f}s")
1664
+
1665
+ @contextmanager
1666
+ def temporary_env(**variables: str) -> Generator[None, None, None]:
1667
+ """临时设置环境变量,退出时恢复"""
1668
+ import os
1669
+ old_values: dict[str, str | None] = {}
1670
+ try:
1671
+ for key, value in variables.items():
1672
+ old_values[key] = os.environ.get(key)
1673
+ os.environ[key] = value
1674
+ yield
1675
+ finally:
1676
+ for key, old_value in old_values.items():
1677
+ if old_value is None:
1678
+ os.environ.pop(key, None)
1679
+ else:
1680
+ os.environ[key] = old_value
1681
+
1682
+ # 使用
1683
+ with timer("data_load") as t:
1684
+ time.sleep(0.1)
1685
+ print(f"Elapsed: {t['elapsed']:.4f}s")
1686
+
1687
+ with temporary_env(DATABASE_URL="sqlite:///test.db", DEBUG="1"):
1688
+ import os
1689
+ print(os.environ["DATABASE_URL"]) # sqlite:///test.db
1690
+ # 退出后环境变量自动恢复
1691
+ ```
1692
+
1693
+ **使用场景**: 文件/数据库/网络连接管理、锁管理、临时状态、事务、测试fixture。
1694
+
1695
+ **注意事项**:
1696
+ - `@contextmanager`适合简单场景,复杂逻辑用类实现
1697
+ - `__exit__`返回`True`会吞掉异常——除非明确需要,否则返回`False`
1698
+ - 支持`async with`需要实现`__aenter__`/`__aexit__`
1699
+
1700
+ ### 5. 协程模式 (Coroutine Patterns)
1701
+
1702
+ **问题描述**: 利用async/await实现高效的并发模式。
1703
+
1704
+ **Python实现**:
1705
+
1706
+ ```python
1707
+ import asyncio
1708
+ from typing import AsyncIterator
1709
+
1710
+ # 异步生产者-消费者模式
1711
+ async def producer(queue: asyncio.Queue[str | None], items: list[str]) -> None:
1712
+ for item in items:
1713
+ await asyncio.sleep(0.1) # 模拟异步IO
1714
+ await queue.put(item)
1715
+ print(f"Produced: {item}")
1716
+ await queue.put(None) # 哨兵值表示结束
1717
+
1718
+ async def consumer(queue: asyncio.Queue[str | None], name: str) -> list[str]:
1719
+ results: list[str] = []
1720
+ while True:
1721
+ item = await queue.get()
1722
+ if item is None:
1723
+ await queue.put(None) # 传递结束信号给其他消费者
1724
+ break
1725
+ print(f"[{name}] Consumed: {item}")
1726
+ results.append(item)
1727
+ queue.task_done()
1728
+ return results
1729
+
1730
+ # 异步迭代器模式
1731
+ async def async_paginate(url: str, page_size: int = 10) -> AsyncIterator[dict]:
1732
+ """异步分页迭代器"""
1733
+ page = 1
1734
+ while True:
1735
+ # 模拟异步API调用
1736
+ await asyncio.sleep(0.05)
1737
+ items = [{"id": (page - 1) * page_size + i} for i in range(page_size)]
1738
+ if page > 3: # 模拟数据结束
1739
+ break
1740
+ for item in items:
1741
+ yield item
1742
+ page += 1
1743
+
1744
+ # 扇出/扇入模式
1745
+ async def fetch_all_parallel(urls: list[str]) -> list[dict]:
1746
+ """并行获取多个URL,收集结果"""
1747
+ async def fetch_one(url: str) -> dict:
1748
+ await asyncio.sleep(0.1) # 模拟网络请求
1749
+ return {"url": url, "status": 200}
1750
+
1751
+ tasks = [asyncio.create_task(fetch_one(url)) for url in urls]
1752
+ results = await asyncio.gather(*tasks, return_exceptions=True)
1753
+ return [r for r in results if isinstance(r, dict)]
1754
+
1755
+ # 使用
1756
+ async def main() -> None:
1757
+ # 生产者-消费者
1758
+ queue: asyncio.Queue[str | None] = asyncio.Queue(maxsize=5)
1759
+ items = [f"task-{i}" for i in range(10)]
1760
+ await asyncio.gather(
1761
+ producer(queue, items),
1762
+ consumer(queue, "worker-1"),
1763
+ consumer(queue, "worker-2"),
1764
+ )
1765
+
1766
+ # 异步迭代
1767
+ async for item in async_paginate("https://api.example.com"):
1768
+ if item["id"] > 5:
1769
+ break
1770
+
1771
+ asyncio.run(main())
1772
+ ```
1773
+
1774
+ **使用场景**: Web爬虫、API聚合、实时数据流处理、WebSocket服务。
1775
+
1776
+ **注意事项**:
1777
+ - 不要在async函数中调用阻塞IO——使用`run_in_executor`包装
1778
+ - `asyncio.gather`的`return_exceptions=True`防止一个失败导致全部取消
1779
+ - 使用`asyncio.Semaphore`限制并发度
1780
+
1781
+ ### 6. 依赖注入模式 (Dependency Injection)
1782
+
1783
+ **问题描述**: 将依赖的创建与使用分离,提高可测试性和灵活性。
1784
+
1785
+ **Python实现**:
1786
+
1787
+ ```python
1788
+ from __future__ import annotations
1789
+ from typing import Protocol, Callable, Any, TypeVar
1790
+ from dataclasses import dataclass, field
1791
+
1792
+ T = TypeVar("T")
1793
+
1794
+ class Repository(Protocol):
1795
+ def find_by_id(self, entity_id: str) -> dict | None: ...
1796
+ def save(self, entity: dict) -> None: ...
1797
+
1798
+ class NotificationSender(Protocol):
1799
+ def send(self, recipient: str, message: str) -> bool: ...
1800
+
1801
+ # 简易DI容器
1802
+ class Container:
1803
+ def __init__(self) -> None:
1804
+ self._factories: dict[type, Callable[[], Any]] = {}
1805
+ self._singletons: dict[type, Any] = {}
1806
+
1807
+ def register(self, interface: type, factory: Callable[[], Any], singleton: bool = False) -> None:
1808
+ if singleton:
1809
+ self._factories[interface] = factory
1810
+ # 延迟创建
1811
+ else:
1812
+ self._factories[interface] = factory
1813
+
1814
+ def register_singleton(self, interface: type, factory: Callable[[], Any]) -> None:
1815
+ self._factories[interface] = factory
1816
+
1817
+ def resolve(self, interface: type[T]) -> T:
1818
+ if interface in self._singletons:
1819
+ return self._singletons[interface]
1820
+ factory = self._factories.get(interface)
1821
+ if factory is None:
1822
+ raise KeyError(f"No registration for {interface}")
1823
+ instance = factory()
1824
+ return instance
1825
+
1826
+ # 具体实现
1827
+ class PostgresRepository:
1828
+ def __init__(self, dsn: str = "postgresql://localhost/mydb") -> None:
1829
+ self.dsn = dsn
1830
+ def find_by_id(self, entity_id: str) -> dict | None:
1831
+ return {"id": entity_id, "data": "from postgres"}
1832
+ def save(self, entity: dict) -> None:
1833
+ print(f"Saved to Postgres: {entity}")
1834
+
1835
+ class InMemoryRepository:
1836
+ """测试用内存存储"""
1837
+ def __init__(self) -> None:
1838
+ self._store: dict[str, dict] = {}
1839
+ def find_by_id(self, entity_id: str) -> dict | None:
1840
+ return self._store.get(entity_id)
1841
+ def save(self, entity: dict) -> None:
1842
+ self._store[entity["id"]] = entity
1843
+
1844
+ class EmailSender:
1845
+ def send(self, recipient: str, message: str) -> bool:
1846
+ print(f"Email to {recipient}: {message}")
1847
+ return True
1848
+
1849
+ @dataclass
1850
+ class UserService:
1851
+ """通过构造函数注入依赖"""
1852
+ repo: Repository
1853
+ notifier: NotificationSender
1854
+
1855
+ def create_user(self, name: str, email: str) -> dict:
1856
+ user = {"id": f"user-{hash(name) % 10000}", "name": name, "email": email}
1857
+ self.repo.save(user)
1858
+ self.notifier.send(email, f"Welcome, {name}!")
1859
+ return user
1860
+
1861
+ # 生产环境配置
1862
+ container = Container()
1863
+ container.register(Repository, lambda: PostgresRepository())
1864
+ container.register(NotificationSender, lambda: EmailSender())
1865
+ service = UserService(
1866
+ repo=container.resolve(Repository),
1867
+ notifier=container.resolve(NotificationSender),
1868
+ )
1869
+
1870
+ # 测试环境:替换为mock实现
1871
+ test_repo = InMemoryRepository()
1872
+ test_service = UserService(repo=test_repo, notifier=EmailSender())
1873
+ ```
1874
+
1875
+ **使用场景**: 服务层构造、测试替身注入、配置驱动实现选择、插件系统。
1876
+
1877
+ **注意事项**:
1878
+ - Python中构造函数注入(传参)是最简单有效的DI方式
1879
+ - 避免过度工程化——大多数Python项目不需要完整的DI框架
1880
+ - 如需框架级DI,考虑`dependency-injector`或`inject`库
1881
+
1882
+ ---
1883
+
1884
+ ## 架构模式
1885
+
1886
+ ### 1. 仓储模式 (Repository)
1887
+
1888
+ **问题描述**: 将数据访问逻辑与业务逻辑分离,提供集合式接口操作持久化数据。
1889
+
1890
+ **Python实现**:
1891
+
1892
+ ```python
1893
+ from __future__ import annotations
1894
+ from typing import Protocol, TypeVar, Generic
1895
+ from dataclasses import dataclass, field
1896
+ from abc import abstractmethod
1897
+
1898
+ T = TypeVar("T")
1899
+
1900
+ class Repository(Protocol[T]):
1901
+ def get(self, entity_id: str) -> T | None: ...
1902
+ def list(self, offset: int = 0, limit: int = 100) -> list[T]: ...
1903
+ def add(self, entity: T) -> None: ...
1904
+ def update(self, entity: T) -> None: ...
1905
+ def delete(self, entity_id: str) -> bool: ...
1906
+
1907
+ @dataclass
1908
+ class Order:
1909
+ id: str
1910
+ customer_id: str
1911
+ items: list[dict] = field(default_factory=list)
1912
+ total: float = 0.0
1913
+ status: str = "pending"
1914
+
1915
+ class InMemoryOrderRepository:
1916
+ """内存仓储——用于测试和原型"""
1917
+ def __init__(self) -> None:
1918
+ self._store: dict[str, Order] = {}
1919
+
1920
+ def get(self, entity_id: str) -> Order | None:
1921
+ return self._store.get(entity_id)
1922
+
1923
+ def list(self, offset: int = 0, limit: int = 100) -> list[Order]:
1924
+ orders = sorted(self._store.values(), key=lambda o: o.id)
1925
+ return orders[offset:offset + limit]
1926
+
1927
+ def add(self, entity: Order) -> None:
1928
+ if entity.id in self._store:
1929
+ raise ValueError(f"Order {entity.id} already exists")
1930
+ self._store[entity.id] = entity
1931
+
1932
+ def update(self, entity: Order) -> None:
1933
+ if entity.id not in self._store:
1934
+ raise ValueError(f"Order {entity.id} not found")
1935
+ self._store[entity.id] = entity
1936
+
1937
+ def delete(self, entity_id: str) -> bool:
1938
+ return self._store.pop(entity_id, None) is not None
1939
+
1940
+ class SQLOrderRepository:
1941
+ """SQL仓储——实际生产使用"""
1942
+ def __init__(self, session) -> None:
1943
+ self._session = session
1944
+
1945
+ def get(self, entity_id: str) -> Order | None:
1946
+ row = self._session.execute(
1947
+ "SELECT * FROM orders WHERE id = :id", {"id": entity_id}
1948
+ ).fetchone()
1949
+ return self._row_to_order(row) if row else None
1950
+
1951
+ def list(self, offset: int = 0, limit: int = 100) -> list[Order]:
1952
+ rows = self._session.execute(
1953
+ "SELECT * FROM orders ORDER BY id LIMIT :limit OFFSET :offset",
1954
+ {"limit": limit, "offset": offset},
1955
+ ).fetchall()
1956
+ return [self._row_to_order(r) for r in rows]
1957
+
1958
+ def add(self, entity: Order) -> None:
1959
+ self._session.execute(
1960
+ "INSERT INTO orders (id, customer_id, total, status) VALUES (:id, :cid, :total, :status)",
1961
+ {"id": entity.id, "cid": entity.customer_id, "total": entity.total, "status": entity.status},
1962
+ )
1963
+
1964
+ def update(self, entity: Order) -> None:
1965
+ self._session.execute(
1966
+ "UPDATE orders SET total = :total, status = :status WHERE id = :id",
1967
+ {"id": entity.id, "total": entity.total, "status": entity.status},
1968
+ )
1969
+
1970
+ def delete(self, entity_id: str) -> bool:
1971
+ result = self._session.execute(
1972
+ "DELETE FROM orders WHERE id = :id", {"id": entity_id}
1973
+ )
1974
+ return result.rowcount > 0
1975
+
1976
+ @staticmethod
1977
+ def _row_to_order(row) -> Order:
1978
+ return Order(id=row.id, customer_id=row.customer_id, total=row.total, status=row.status)
1979
+ ```
1980
+
1981
+ **使用场景**: 领域驱动设计中的聚合持久化、多数据源抽象、测试隔离。
1982
+
1983
+ **注意事项**:
1984
+ - 仓储接口应面向领域语言,而非SQL语义
1985
+ - 一个聚合根对应一个仓储
1986
+ - 查询复杂度高时可引入规约模式(Specification)
1987
+
1988
+ ### 2. 工作单元模式 (Unit of Work)
1989
+
1990
+ **问题描述**: 跟踪业务事务中所有受影响的对象,协调变更的持久化。
1991
+
1992
+ **Python实现**:
1993
+
1994
+ ```python
1995
+ from __future__ import annotations
1996
+ from contextlib import contextmanager
1997
+ from typing import Generator
1998
+
1999
+ class UnitOfWork:
2000
+ """工作单元:收集变更,统一提交或回滚"""
2001
+ def __init__(self, session_factory) -> None:
2002
+ self._session_factory = session_factory
2003
+ self._session = None
2004
+ self._new: list = []
2005
+ self._dirty: list = []
2006
+ self._removed: list = []
2007
+
2008
+ def __enter__(self) -> "UnitOfWork":
2009
+ self._session = self._session_factory()
2010
+ self._new.clear()
2011
+ self._dirty.clear()
2012
+ self._removed.clear()
2013
+ return self
2014
+
2015
+ def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
2016
+ if exc_type:
2017
+ self.rollback()
2018
+ self._session = None
2019
+ return False
2020
+
2021
+ def register_new(self, entity) -> None:
2022
+ self._new.append(entity)
2023
+
2024
+ def register_dirty(self, entity) -> None:
2025
+ if entity not in self._dirty:
2026
+ self._dirty.append(entity)
2027
+
2028
+ def register_removed(self, entity) -> None:
2029
+ self._removed.append(entity)
2030
+
2031
+ def commit(self) -> None:
2032
+ for entity in self._new:
2033
+ self._session.add(entity)
2034
+ for entity in self._dirty:
2035
+ self._session.merge(entity)
2036
+ for entity in self._removed:
2037
+ self._session.delete(entity)
2038
+ self._session.commit()
2039
+ self._new.clear()
2040
+ self._dirty.clear()
2041
+ self._removed.clear()
2042
+
2043
+ def rollback(self) -> None:
2044
+ if self._session:
2045
+ self._session.rollback()
2046
+ self._new.clear()
2047
+ self._dirty.clear()
2048
+ self._removed.clear()
2049
+
2050
+ # 使用
2051
+ # with UnitOfWork(session_factory) as uow:
2052
+ # order = uow.orders.get("ORD-001")
2053
+ # order.status = "shipped"
2054
+ # uow.register_dirty(order)
2055
+ # uow.commit()
2056
+ ```
2057
+
2058
+ **使用场景**: 数据库事务管理、批量操作原子性、跨仓储一致性。
2059
+
2060
+ **注意事项**:
2061
+ - SQLAlchemy的`Session`本身就是工作单元的实现
2062
+ - 与仓储模式配合使用,仓储在UoW内操作
2063
+ - 保持事务粒度尽量小
2064
+
2065
+ ### 3. CQRS模式 (Command Query Responsibility Segregation)
2066
+
2067
+ **问题描述**: 将读操作(查询)和写操作(命令)分离为不同的模型。
2068
+
2069
+ **Python实现**:
2070
+
2071
+ ```python
2072
+ from __future__ import annotations
2073
+ from dataclasses import dataclass
2074
+ from typing import Protocol, Any
2075
+
2076
+ # 命令侧(写)
2077
+ @dataclass
2078
+ class CreateOrderCommand:
2079
+ customer_id: str
2080
+ items: list[dict]
2081
+
2082
+ @dataclass
2083
+ class CancelOrderCommand:
2084
+ order_id: str
2085
+ reason: str
2086
+
2087
+ class CommandHandler(Protocol):
2088
+ def handle(self, command: Any) -> None: ...
2089
+
2090
+ class CreateOrderHandler:
2091
+ def __init__(self, repo, event_bus) -> None:
2092
+ self.repo = repo
2093
+ self.event_bus = event_bus
2094
+
2095
+ def handle(self, command: CreateOrderCommand) -> None:
2096
+ order_id = f"ORD-{hash(command.customer_id) % 100000}"
2097
+ order = {
2098
+ "id": order_id,
2099
+ "customer_id": command.customer_id,
2100
+ "items": command.items,
2101
+ "status": "pending",
2102
+ }
2103
+ self.repo.add(order)
2104
+ self.event_bus.publish("order.created", {"order_id": order_id})
2105
+
2106
+ # 查询侧(读)
2107
+ @dataclass
2108
+ class OrderSummaryQuery:
2109
+ customer_id: str
2110
+ status: str | None = None
2111
+
2112
+ @dataclass
2113
+ class OrderSummary:
2114
+ order_id: str
2115
+ total: float
2116
+ status: str
2117
+ item_count: int
2118
+
2119
+ class OrderQueryService:
2120
+ """查询服务:专为读优化的独立模型"""
2121
+ def __init__(self, read_db) -> None:
2122
+ self._db = read_db
2123
+
2124
+ def get_order_summaries(self, query: OrderSummaryQuery) -> list[OrderSummary]:
2125
+ # 读模型可以是反范式化的视图、缓存或搜索索引
2126
+ results = self._db.execute(
2127
+ "SELECT order_id, total, status, item_count FROM order_summaries "
2128
+ "WHERE customer_id = :cid",
2129
+ {"cid": query.customer_id},
2130
+ )
2131
+ return [
2132
+ OrderSummary(
2133
+ order_id=r.order_id,
2134
+ total=r.total,
2135
+ status=r.status,
2136
+ item_count=r.item_count,
2137
+ )
2138
+ for r in results
2139
+ ]
2140
+
2141
+ # 命令总线
2142
+ class CommandBus:
2143
+ def __init__(self) -> None:
2144
+ self._handlers: dict[type, CommandHandler] = {}
2145
+
2146
+ def register(self, command_type: type, handler: CommandHandler) -> None:
2147
+ self._handlers[command_type] = handler
2148
+
2149
+ def dispatch(self, command: Any) -> None:
2150
+ handler = self._handlers.get(type(command))
2151
+ if handler is None:
2152
+ raise ValueError(f"No handler for {type(command).__name__}")
2153
+ handler.handle(command)
2154
+ ```
2155
+
2156
+ **使用场景**: 高读写比系统、需要独立扩展读写的系统、事件驱动架构。
2157
+
2158
+ **注意事项**:
2159
+ - CQRS增加了系统复杂度——只在读写模型差异大时使用
2160
+ - 通常与事件溯源配合,读模型通过事件投影生成
2161
+ - 读写模型最终一致即可,不要追求强一致
2162
+
2163
+ ### 4. 事件溯源模式 (Event Sourcing)
2164
+
2165
+ **问题描述**: 不存储当前状态,而是存储导致当前状态的所有事件序列。
2166
+
2167
+ **Python实现**:
2168
+
2169
+ ```python
2170
+ from __future__ import annotations
2171
+ from dataclasses import dataclass, field
2172
+ from datetime import datetime
2173
+ from typing import Any
2174
+
2175
+ @dataclass(frozen=True)
2176
+ class DomainEvent:
2177
+ event_type: str
2178
+ aggregate_id: str
2179
+ data: dict[str, Any]
2180
+ timestamp: datetime = field(default_factory=datetime.utcnow)
2181
+ version: int = 0
2182
+
2183
+ class EventStore:
2184
+ """事件存储:追加写入,按聚合ID查询"""
2185
+ def __init__(self) -> None:
2186
+ self._events: list[DomainEvent] = []
2187
+
2188
+ def append(self, event: DomainEvent) -> None:
2189
+ self._events.append(event)
2190
+
2191
+ def get_events(self, aggregate_id: str) -> list[DomainEvent]:
2192
+ return [e for e in self._events if e.aggregate_id == aggregate_id]
2193
+
2194
+ class BankAccount:
2195
+ """银行账户聚合:通过事件重建状态"""
2196
+ def __init__(self, account_id: str) -> None:
2197
+ self.account_id = account_id
2198
+ self.balance: float = 0.0
2199
+ self.is_active: bool = False
2200
+ self._pending_events: list[DomainEvent] = []
2201
+ self._version: int = 0
2202
+
2203
+ def apply_event(self, event: DomainEvent) -> None:
2204
+ handler = getattr(self, f"_on_{event.event_type}", None)
2205
+ if handler:
2206
+ handler(event.data)
2207
+ self._version = event.version
2208
+
2209
+ def _on_account_opened(self, data: dict) -> None:
2210
+ self.is_active = True
2211
+ self.balance = data.get("initial_deposit", 0.0)
2212
+
2213
+ def _on_money_deposited(self, data: dict) -> None:
2214
+ self.balance += data["amount"]
2215
+
2216
+ def _on_money_withdrawn(self, data: dict) -> None:
2217
+ self.balance -= data["amount"]
2218
+
2219
+ def _on_account_closed(self, data: dict) -> None:
2220
+ self.is_active = False
2221
+
2222
+ # 命令方法:产生事件
2223
+ def open(self, initial_deposit: float) -> None:
2224
+ if self.is_active:
2225
+ raise ValueError("Account already open")
2226
+ self._raise_event("account_opened", {"initial_deposit": initial_deposit})
2227
+
2228
+ def deposit(self, amount: float) -> None:
2229
+ if not self.is_active:
2230
+ raise ValueError("Account is closed")
2231
+ if amount <= 0:
2232
+ raise ValueError("Amount must be positive")
2233
+ self._raise_event("money_deposited", {"amount": amount})
2234
+
2235
+ def withdraw(self, amount: float) -> None:
2236
+ if not self.is_active:
2237
+ raise ValueError("Account is closed")
2238
+ if amount > self.balance:
2239
+ raise ValueError("Insufficient funds")
2240
+ self._raise_event("money_withdrawn", {"amount": amount})
2241
+
2242
+ def _raise_event(self, event_type: str, data: dict) -> None:
2243
+ event = DomainEvent(
2244
+ event_type=event_type,
2245
+ aggregate_id=self.account_id,
2246
+ data=data,
2247
+ version=self._version + 1,
2248
+ )
2249
+ self.apply_event(event)
2250
+ self._pending_events.append(event)
2251
+
2252
+ def flush_events(self) -> list[DomainEvent]:
2253
+ events = self._pending_events[:]
2254
+ self._pending_events.clear()
2255
+ return events
2256
+
2257
+ @classmethod
2258
+ def from_events(cls, account_id: str, events: list[DomainEvent]) -> BankAccount:
2259
+ """从事件流重建聚合状态"""
2260
+ account = cls(account_id)
2261
+ for event in events:
2262
+ account.apply_event(event)
2263
+ return account
2264
+
2265
+ # 使用
2266
+ store = EventStore()
2267
+ account = BankAccount("ACC-001")
2268
+ account.open(1000.0)
2269
+ account.deposit(500.0)
2270
+ account.withdraw(200.0)
2271
+
2272
+ # 持久化事件
2273
+ for event in account.flush_events():
2274
+ store.append(event)
2275
+
2276
+ # 从事件重建状态
2277
+ rebuilt = BankAccount.from_events("ACC-001", store.get_events("ACC-001"))
2278
+ print(rebuilt.balance) # 1300.0
2279
+ ```
2280
+
2281
+ **使用场景**: 金融系统、审计追踪、时间旅行调试、分布式系统状态同步。
2282
+
2283
+ **注意事项**:
2284
+ - 事件一旦持久化就不可变——修正错误通过补偿事件
2285
+ - 事件流过长时使用快照优化重建性能
2286
+ - 事件schema的演化需要版本管理
2287
+
2288
+ ### 5. 领域驱动设计在Python中的实现 (DDD)
2289
+
2290
+ **问题描述**: 将复杂业务逻辑组织为领域模型,使代码结构反映业务概念。
2291
+
2292
+ **Python实现**:
2293
+
2294
+ ```python
2295
+ from __future__ import annotations
2296
+ from dataclasses import dataclass, field
2297
+ from datetime import datetime
2298
+ from typing import NewType
2299
+ from enum import Enum, auto
2300
+
2301
+ # 值对象
2302
+ OrderId = NewType("OrderId", str)
2303
+ CustomerId = NewType("CustomerId", str)
2304
+
2305
+ @dataclass(frozen=True)
2306
+ class Money:
2307
+ """值对象:不可变,通过值比较"""
2308
+ amount: float
2309
+ currency: str = "CNY"
2310
+
2311
+ def __add__(self, other: Money) -> Money:
2312
+ if self.currency != other.currency:
2313
+ raise ValueError(f"Cannot add {self.currency} and {other.currency}")
2314
+ return Money(self.amount + other.amount, self.currency)
2315
+
2316
+ def __mul__(self, factor: int | float) -> Money:
2317
+ return Money(round(self.amount * factor, 2), self.currency)
2318
+
2319
+ class OrderStatus(Enum):
2320
+ DRAFT = auto()
2321
+ CONFIRMED = auto()
2322
+ PAID = auto()
2323
+ SHIPPED = auto()
2324
+ COMPLETED = auto()
2325
+ CANCELLED = auto()
2326
+
2327
+ # 实体
2328
+ @dataclass
2329
+ class OrderItem:
2330
+ product_id: str
2331
+ product_name: str
2332
+ unit_price: Money
2333
+ quantity: int
2334
+
2335
+ @property
2336
+ def subtotal(self) -> Money:
2337
+ return self.unit_price * self.quantity
2338
+
2339
+ # 聚合根
2340
+ @dataclass
2341
+ class Order:
2342
+ """订单聚合根:封装所有业务不变量"""
2343
+ id: OrderId
2344
+ customer_id: CustomerId
2345
+ items: list[OrderItem] = field(default_factory=list)
2346
+ status: OrderStatus = OrderStatus.DRAFT
2347
+ created_at: datetime = field(default_factory=datetime.utcnow)
2348
+ _events: list[dict] = field(default_factory=list, repr=False)
2349
+
2350
+ @property
2351
+ def total(self) -> Money:
2352
+ if not self.items:
2353
+ return Money(0.0)
2354
+ result = Money(0.0)
2355
+ for item in self.items:
2356
+ result = result + item.subtotal
2357
+ return result
2358
+
2359
+ def add_item(self, product_id: str, name: str, price: Money, qty: int) -> None:
2360
+ if self.status != OrderStatus.DRAFT:
2361
+ raise ValueError("Can only add items to draft orders")
2362
+ if qty <= 0:
2363
+ raise ValueError("Quantity must be positive")
2364
+ self.items.append(OrderItem(product_id, name, price, qty))
2365
+
2366
+ def confirm(self) -> None:
2367
+ if self.status != OrderStatus.DRAFT:
2368
+ raise ValueError(f"Cannot confirm order in {self.status.name} status")
2369
+ if not self.items:
2370
+ raise ValueError("Cannot confirm empty order")
2371
+ self.status = OrderStatus.CONFIRMED
2372
+ self._events.append({"type": "order.confirmed", "order_id": self.id})
2373
+
2374
+ def cancel(self, reason: str) -> None:
2375
+ if self.status in {OrderStatus.SHIPPED, OrderStatus.COMPLETED}:
2376
+ raise ValueError(f"Cannot cancel order in {self.status.name} status")
2377
+ self.status = OrderStatus.CANCELLED
2378
+ self._events.append({
2379
+ "type": "order.cancelled",
2380
+ "order_id": self.id,
2381
+ "reason": reason,
2382
+ })
2383
+
2384
+ def collect_events(self) -> list[dict]:
2385
+ events = self._events[:]
2386
+ self._events.clear()
2387
+ return events
2388
+
2389
+ # 领域服务
2390
+ class PricingService:
2391
+ """领域服务:跨聚合的业务逻辑"""
2392
+ def calculate_discount(self, order: Order, customer_tier: str) -> Money:
2393
+ base = order.total
2394
+ discount_rate = {"bronze": 0.0, "silver": 0.05, "gold": 0.10, "platinum": 0.15}
2395
+ rate = discount_rate.get(customer_tier, 0.0)
2396
+ return Money(round(base.amount * rate, 2), base.currency)
2397
+
2398
+ # 使用
2399
+ order = Order(id=OrderId("ORD-001"), customer_id=CustomerId("CUST-042"))
2400
+ order.add_item("PROD-1", "Widget", Money(29.90), 3)
2401
+ order.add_item("PROD-2", "Gadget", Money(99.00), 1)
2402
+ print(order.total) # Money(amount=188.7, currency='CNY')
2403
+ order.confirm()
2404
+ events = order.collect_events() # [{'type': 'order.confirmed', ...}]
2405
+ ```
2406
+
2407
+ **使用场景**: 复杂业务系统(电商、金融、物流)、需要长期维护的核心域。
2408
+
2409
+ **注意事项**:
2410
+ - 值对象必须不可变(`frozen=True`)
2411
+ - 聚合根是事务一致性的边界——一个事务只修改一个聚合
2412
+ - 跨聚合的业务规则放在领域服务中
2413
+ - 不要对所有代码都用DDD——只对核心复杂域使用
2414
+
2415
+ ---
2416
+
2417
+ ## 反模式
2418
+
2419
+ ### 1. God Object(上帝对象)
2420
+
2421
+ **问题描述**: 一个类承担了过多职责,知道太多、做太多。
2422
+
2423
+ **识别信号**:
2424
+ - 文件超过1000行
2425
+ - 类有20+个方法
2426
+ - 构造函数注入10+个依赖
2427
+ - 修改任何功能都要改这个类
2428
+
2429
+ **修复方案**: 按职责拆分为多个协作类,使用外观模式提供统一入口。
2430
+
2431
+ ```python
2432
+ # 反模式
2433
+ class OrderManager:
2434
+ def create_order(self): ...
2435
+ def process_payment(self): ...
2436
+ def send_notification(self): ...
2437
+ def generate_invoice(self): ...
2438
+ def update_inventory(self): ...
2439
+ def calculate_shipping(self): ...
2440
+ def apply_discount(self): ...
2441
+ def handle_refund(self): ...
2442
+ # ... 50+ methods
2443
+
2444
+ # 正确做法:拆分为独立服务
2445
+ class OrderService:
2446
+ def __init__(self, payment: PaymentService, inventory: InventoryService):
2447
+ self.payment = payment
2448
+ self.inventory = inventory
2449
+
2450
+ def create_order(self, items): ...
2451
+
2452
+ class PaymentService:
2453
+ def process(self, order): ...
2454
+ def refund(self, order): ...
2455
+
2456
+ class InventoryService:
2457
+ def reserve(self, items): ...
2458
+ def release(self, items): ...
2459
+ ```
2460
+
2461
+ ### 2. Spaghetti Code(意大利面代码)
2462
+
2463
+ **问题描述**: 缺乏清晰结构,控制流复杂交织,难以追踪执行路径。
2464
+
2465
+ **识别信号**:
2466
+ - 函数超过50行
2467
+ - 深层嵌套(if-else超过4层)
2468
+ - 大量全局变量
2469
+ - goto风格的控制流(异常用于流程控制)
2470
+
2471
+ **修复方案**: 提取函数、使用早返回、引入状态模式或策略模式。
2472
+
2473
+ ```python
2474
+ # 反模式:深层嵌套
2475
+ def process_order(order):
2476
+ if order:
2477
+ if order.items:
2478
+ if order.customer:
2479
+ if order.customer.is_active:
2480
+ if order.total > 0:
2481
+ # 实际逻辑深埋在这里
2482
+ pass
2483
+
2484
+ # 正确做法:卫语句 + 早返回
2485
+ def process_order(order):
2486
+ if not order:
2487
+ raise ValueError("Order is required")
2488
+ if not order.items:
2489
+ raise ValueError("Order must have items")
2490
+ if not order.customer or not order.customer.is_active:
2491
+ raise ValueError("Active customer required")
2492
+ if order.total <= 0:
2493
+ raise ValueError("Order total must be positive")
2494
+ # 实际逻辑在最外层
2495
+ _execute_order(order)
2496
+ ```
2497
+
2498
+ ### 3. 过度设计 (Over-Engineering)
2499
+
2500
+ **问题描述**: 为未来可能永远不会出现的需求增加不必要的抽象层。
2501
+
2502
+ **识别信号**:
2503
+ - 只有一个实现的接口/抽象类
2504
+ - 为3个字段创建Builder模式
2505
+ - 未使用的扩展点
2506
+ - "以后可能需要"的抽象
2507
+
2508
+ **修复方案**: 遵循YAGNI(You Ain't Gonna Need It),先实现最简方案,当第三次遇到相似需求时再抽象。
2509
+
2510
+ ```python
2511
+ # 过度设计:只有一种通知方式却创建了完整的策略体系
2512
+ class NotificationStrategyFactory(AbstractNotificationFactory):
2513
+ ... # 100行只为发一封邮件
2514
+
2515
+ # 正确做法:直接写
2516
+ def send_welcome_email(user_email: str, user_name: str) -> None:
2517
+ # 直接发邮件,等真正需要SMS时再抽象
2518
+ smtp.send(to=user_email, subject="Welcome", body=f"Hi {user_name}")
2519
+ ```
2520
+
2521
+ ### 4. 过早抽象 (Premature Abstraction)
2522
+
2523
+ **问题描述**: 在只有一个用例时就创建通用框架,导致抽象与实际需求不匹配。
2524
+
2525
+ **修复方案**: Rule of Three——等看到三个相似场景后再提取抽象。
2526
+
2527
+ ### 5. Singleton滥用
2528
+
2529
+ **问题描述**: 将单例当作全局变量使用,导致隐式依赖、测试困难、并发问题。
2530
+
2531
+ **识别信号**:
2532
+ - 在函数内部直接调用`XxxManager.instance()`而非通过参数接收
2533
+ - 单例持有可变状态且被多线程访问
2534
+ - 测试时需要"重置"单例状态
2535
+
2536
+ **修复方案**: 用依赖注入替代。将单例降级为"只创建一次"的普通对象,通过参数传递。
2537
+
2538
+ ```python
2539
+ # 反模式:到处直接访问单例
2540
+ def process_payment(amount):
2541
+ config = AppConfig.instance() # 隐式依赖
2542
+ db = DatabasePool.instance() # 隐式依赖
2543
+ logger = Logger.instance() # 隐式依赖
2544
+ ...
2545
+
2546
+ # 正确做法:显式依赖
2547
+ def process_payment(amount, config, db, logger):
2548
+ ...
2549
+
2550
+ # 在组合根(入口点)创建并注入
2551
+ config = AppConfig()
2552
+ db = DatabasePool(config.db_url)
2553
+ logger = Logger(config.log_level)
2554
+ process_payment(100.0, config, db, logger)
2555
+ ```
2556
+
2557
+ ---
2558
+
2559
+ ## 实战案例:用设计模式重构支付系统
2560
+
2561
+ ### 重构前:混乱的支付处理
2562
+
2563
+ ```python
2564
+ # payment_processor.py - 重构前(典型的God Object + Spaghetti Code)
2565
+ class PaymentProcessor:
2566
+ def __init__(self):
2567
+ self.db = DatabasePool.instance()
2568
+ self.config = AppConfig.instance()
2569
+ self.logger = Logger.instance()
2570
+
2571
+ def process(self, order_id, payment_type, card_number=None,
2572
+ alipay_id=None, wechat_openid=None, amount=None):
2573
+ # 800行方法,处理所有支付类型
2574
+ order = self.db.query(f"SELECT * FROM orders WHERE id = '{order_id}'") # SQL注入
2575
+ if not order:
2576
+ return {"success": False, "error": "Order not found"}
2577
+
2578
+ if payment_type == "credit_card":
2579
+ if not card_number:
2580
+ return {"success": False, "error": "Card number required"}
2581
+ # 100行信用卡处理逻辑...
2582
+ result = self._call_stripe(card_number, amount)
2583
+ if result["status"] == "success":
2584
+ self.db.execute(f"UPDATE orders SET status='paid' WHERE id='{order_id}'")
2585
+ self.db.execute(f"INSERT INTO payments ...")
2586
+ # 发送邮件通知
2587
+ import smtplib
2588
+ server = smtplib.SMTP("smtp.example.com")
2589
+ server.sendmail("noreply@shop.com", order["email"], "Payment received")
2590
+ return {"success": True}
2591
+ else:
2592
+ return {"success": False, "error": result["error"]}
2593
+ elif payment_type == "alipay":
2594
+ # 又是100行支付宝逻辑...
2595
+ pass
2596
+ elif payment_type == "wechat":
2597
+ # 又是100行微信逻辑...
2598
+ pass
2599
+ else:
2600
+ return {"success": False, "error": "Unknown payment type"}
2601
+ ```
2602
+
2603
+ ### 重构后:清晰的模式应用
2604
+
2605
+ ```python
2606
+ # domain/models.py - 值对象和实体
2607
+ from dataclasses import dataclass
2608
+ from enum import Enum, auto
2609
+
2610
+ class PaymentMethod(Enum):
2611
+ CREDIT_CARD = auto()
2612
+ ALIPAY = auto()
2613
+ WECHAT_PAY = auto()
2614
+
2615
+ @dataclass(frozen=True)
2616
+ class Money:
2617
+ amount: float
2618
+ currency: str = "CNY"
2619
+
2620
+ def __post_init__(self):
2621
+ if self.amount < 0:
2622
+ raise ValueError("Amount cannot be negative")
2623
+
2624
+ @dataclass
2625
+ class PaymentResult:
2626
+ success: bool
2627
+ transaction_id: str | None = None
2628
+ error: str | None = None
2629
+
2630
+
2631
+ # domain/gateway.py - 策略模式:支付网关
2632
+ from typing import Protocol
2633
+
2634
+ class PaymentGateway(Protocol):
2635
+ """支付网关协议——每种支付方式一个实现"""
2636
+ def charge(self, amount: Money, credentials: dict) -> PaymentResult: ...
2637
+ def refund(self, transaction_id: str, amount: Money) -> PaymentResult: ...
2638
+
2639
+ class StripeGateway:
2640
+ def __init__(self, api_key: str) -> None:
2641
+ self._api_key = api_key
2642
+
2643
+ def charge(self, amount: Money, credentials: dict) -> PaymentResult:
2644
+ card = credentials.get("card_number")
2645
+ if not card:
2646
+ return PaymentResult(success=False, error="Card number required")
2647
+ # 调用Stripe API
2648
+ return PaymentResult(success=True, transaction_id="stripe_txn_001")
2649
+
2650
+ def refund(self, transaction_id: str, amount: Money) -> PaymentResult:
2651
+ return PaymentResult(success=True, transaction_id=f"refund_{transaction_id}")
2652
+
2653
+ class AlipayGateway:
2654
+ def __init__(self, app_id: str, private_key: str) -> None:
2655
+ self._app_id = app_id
2656
+ self._private_key = private_key
2657
+
2658
+ def charge(self, amount: Money, credentials: dict) -> PaymentResult:
2659
+ return PaymentResult(success=True, transaction_id="alipay_txn_001")
2660
+
2661
+ def refund(self, transaction_id: str, amount: Money) -> PaymentResult:
2662
+ return PaymentResult(success=True, transaction_id=f"refund_{transaction_id}")
2663
+
2664
+ class WechatPayGateway:
2665
+ def __init__(self, mch_id: str, api_key: str) -> None:
2666
+ self._mch_id = mch_id
2667
+ self._api_key = api_key
2668
+
2669
+ def charge(self, amount: Money, credentials: dict) -> PaymentResult:
2670
+ return PaymentResult(success=True, transaction_id="wechat_txn_001")
2671
+
2672
+ def refund(self, transaction_id: str, amount: Money) -> PaymentResult:
2673
+ return PaymentResult(success=True, transaction_id=f"refund_{transaction_id}")
2674
+
2675
+
2676
+ # domain/repository.py - 仓储模式
2677
+ class OrderRepository(Protocol):
2678
+ def get(self, order_id: str) -> dict | None: ...
2679
+ def update_status(self, order_id: str, status: str) -> None: ...
2680
+
2681
+ class PaymentRepository(Protocol):
2682
+ def save(self, payment: dict) -> None: ...
2683
+ def get_by_order(self, order_id: str) -> dict | None: ...
2684
+
2685
+
2686
+ # domain/notification.py - 观察者模式:支付事件通知
2687
+ from collections import defaultdict
2688
+ from typing import Callable, Any
2689
+
2690
+ class PaymentEventBus:
2691
+ def __init__(self) -> None:
2692
+ self._handlers: dict[str, list[Callable]] = defaultdict(list)
2693
+
2694
+ def subscribe(self, event: str, handler: Callable) -> None:
2695
+ self._handlers[event].append(handler)
2696
+
2697
+ def publish(self, event: str, data: dict[str, Any]) -> None:
2698
+ for handler in self._handlers.get(event, []):
2699
+ try:
2700
+ handler(data)
2701
+ except Exception as e:
2702
+ # 通知失败不应影响支付流程
2703
+ print(f"Handler error: {e}")
2704
+
2705
+ def email_notification_handler(data: dict) -> None:
2706
+ print(f"Email: Payment {data['transaction_id']} for order {data['order_id']}")
2707
+
2708
+ def inventory_update_handler(data: dict) -> None:
2709
+ print(f"Inventory: Release reserved items for order {data['order_id']}")
2710
+
2711
+ def audit_log_handler(data: dict) -> None:
2712
+ print(f"Audit: Payment event recorded for order {data['order_id']}")
2713
+
2714
+
2715
+ # application/service.py - 外观模式:统一支付服务入口
2716
+ class PaymentService:
2717
+ """支付服务:协调网关、仓储和事件"""
2718
+ def __init__(
2719
+ self,
2720
+ gateways: dict[PaymentMethod, PaymentGateway],
2721
+ order_repo: OrderRepository,
2722
+ payment_repo: PaymentRepository,
2723
+ event_bus: PaymentEventBus,
2724
+ ) -> None:
2725
+ self._gateways = gateways
2726
+ self._orders = order_repo
2727
+ self._payments = payment_repo
2728
+ self._events = event_bus
2729
+
2730
+ def process_payment(
2731
+ self,
2732
+ order_id: str,
2733
+ method: PaymentMethod,
2734
+ credentials: dict,
2735
+ ) -> PaymentResult:
2736
+ # 1. 查找订单
2737
+ order = self._orders.get(order_id)
2738
+ if order is None:
2739
+ return PaymentResult(success=False, error="Order not found")
2740
+
2741
+ # 2. 选择支付网关(策略模式)
2742
+ gateway = self._gateways.get(method)
2743
+ if gateway is None:
2744
+ return PaymentResult(success=False, error=f"Unsupported: {method.name}")
2745
+
2746
+ # 3. 执行支付
2747
+ amount = Money(order["total"])
2748
+ result = gateway.charge(amount, credentials)
2749
+
2750
+ if not result.success:
2751
+ return result
2752
+
2753
+ # 4. 持久化(仓储模式)
2754
+ self._orders.update_status(order_id, "paid")
2755
+ self._payments.save({
2756
+ "order_id": order_id,
2757
+ "transaction_id": result.transaction_id,
2758
+ "amount": amount.amount,
2759
+ "method": method.name,
2760
+ })
2761
+
2762
+ # 5. 发布事件(观察者模式)
2763
+ self._events.publish("payment.completed", {
2764
+ "order_id": order_id,
2765
+ "transaction_id": result.transaction_id,
2766
+ "amount": amount.amount,
2767
+ })
2768
+
2769
+ return result
2770
+
2771
+
2772
+ # composition_root.py - 组合根:在入口点组装所有依赖
2773
+ def create_payment_service(config: dict) -> PaymentService:
2774
+ """依赖注入:在应用入口组装整个对象图"""
2775
+ gateways = {
2776
+ PaymentMethod.CREDIT_CARD: StripeGateway(config["stripe_key"]),
2777
+ PaymentMethod.ALIPAY: AlipayGateway(config["alipay_app_id"], config["alipay_key"]),
2778
+ PaymentMethod.WECHAT_PAY: WechatPayGateway(config["wechat_mch_id"], config["wechat_key"]),
2779
+ }
2780
+
2781
+ event_bus = PaymentEventBus()
2782
+ event_bus.subscribe("payment.completed", email_notification_handler)
2783
+ event_bus.subscribe("payment.completed", inventory_update_handler)
2784
+ event_bus.subscribe("payment.completed", audit_log_handler)
2785
+
2786
+ # order_repo和payment_repo从实际数据库创建
2787
+ # 此处省略,实际使用SQLOrderRepository等
2788
+
2789
+ return PaymentService(
2790
+ gateways=gateways,
2791
+ order_repo=order_repo,
2792
+ payment_repo=payment_repo,
2793
+ event_bus=event_bus,
2794
+ )
2795
+ ```
2796
+
2797
+ ### 重构收益总结
2798
+
2799
+ | 维度 | 重构前 | 重构后 |
2800
+ |------|--------|--------|
2801
+ | 可测试性 | 无法单测(依赖全局单例) | 每个组件独立可测 |
2802
+ | 扩展性 | 添加支付方式需修改核心类 | 新增Gateway实现即可 |
2803
+ | 安全性 | SQL注入、硬编码凭证 | 参数化查询、配置注入 |
2804
+ | 职责清晰度 | 单文件800行 | 每个模块不超过100行 |
2805
+ | 通知扩展 | 硬编码邮件发送 | 订阅事件即可添加通知渠道 |
2806
+ | 应用模式 | 无 | 策略、仓储、观察者、外观、DI |
2807
+
2808
+ ---
2809
+
2810
+ ## Agent Checklist
2811
+
2812
+ 在代码审查和架构设计中,使用以下检查清单评估设计模式的应用质量:
2813
+
2814
+ ### 创建型模式检查
2815
+ - [ ] 工厂方法是否使用字典注册表而非冗长的if-elif链
2816
+ - [ ] 单例实现是否优先使用模块级变量
2817
+ - [ ] 单例是否可以被依赖注入替代以提高可测试性
2818
+ - [ ] Builder是否在构造函数参数超过5个或有构造验证时才使用
2819
+ - [ ] 原型模式是否正确使用了`copy.deepcopy`处理可变嵌套对象
2820
+
2821
+ ### 结构型模式检查
2822
+ - [ ] 装饰器是否使用了`@functools.wraps`保留元信息
2823
+ - [ ] 装饰器堆叠顺序是否正确(最内层先执行)
2824
+ - [ ] 适配器是否使用组合而非继承
2825
+ - [ ] 外观是否只封装常见工作流,而非试图代替子系统全部功能
2826
+ - [ ] 代理与装饰器是否正确区分(控制访问 vs 增强功能)
2827
+
2828
+ ### 行为型模式检查
2829
+ - [ ] 策略模式是否优先使用函数/callable而非单方法类
2830
+ - [ ] 观察者/事件总线是否有防止内存泄漏的措施(取消订阅、weakref)
2831
+ - [ ] 命令模式的undo是否捕获了执行时的完整状态
2832
+ - [ ] 状态机的转换是否显式定义且不允许非法跳跃
2833
+ - [ ] 责任链中的闭包是否正确绑定了变量(使用默认参数)
2834
+
2835
+ ### Python特有模式检查
2836
+ - [ ] Mixin类是否遵守了"不独立实例化"原则
2837
+ - [ ] 描述符是否使用了`__set_name__`自动获取属性名
2838
+ - [ ] 元类是否可以用`__init_subclass__`替代
2839
+ - [ ] 上下文管理器的`__exit__`是否正确处理了异常(不意外吞掉)
2840
+ - [ ] 异步代码是否避免了在async函数中调用阻塞IO
2841
+
2842
+ ### 架构模式检查
2843
+ - [ ] 仓储接口是否面向领域语言而非SQL语义
2844
+ - [ ] 工作单元是否在事务边界内正确管理了提交和回滚
2845
+ - [ ] CQRS是否只在读写模型确实不同时才使用
2846
+ - [ ] 事件溯源的事件schema是否有版本管理
2847
+ - [ ] DDD值对象是否不可变(`frozen=True`)
2848
+
2849
+ ### 反模式检查
2850
+ - [ ] 是否存在超过500行的单个类文件(God Object信号)
2851
+ - [ ] 是否存在超过4层的if-else嵌套(Spaghetti信号)
2852
+ - [ ] 是否存在只有一个实现的抽象接口(过度设计信号)
2853
+ - [ ] 是否存在函数内部直接调用`.instance()`的单例访问(隐式依赖信号)
2854
+ - [ ] 抽象是否在看到至少三个相似场景后才引入(Rule of Three)