🧩 什么是 Mixin 设计模式?
一句话定义:
Mixin 是一种"只提供能力、不独立存在"的类,用来给其他类横向加功能。
它不是:
-
❌ 业务对象
-
❌ 完整组件
它是:
-
✅ 行为片段(capability)
-
✅ 可组合的能力模块
📐 Mixin vs 继承(先破一个常见误区)
❌ 传统继承(问题多)
BasePage
├── LoginPage
│ └── LoginPageWithRetry
│ └── LoginPageWithRetryAndLog
问题:
-
继承链爆炸
-
横向能力无法复用
-
测试维护成本极高
✅ Mixin(组合能力)
Page = BasePage
+ RetryMixin
+ LoggingMixin
+ AIAssistMixin
📌 能力是"加上去的",不是"继承来的"
🧠 Mixin 的三个核心特征
| 特征 | 说明 |
|---|---|
| 不独立实例化 | 不单独 new |
| 不保存核心状态 | 只用宿主对象 |
| 专注一个能力 | 单一职责 |
🐍 Python 中的 Mixin(标准写法)
1️⃣ 定义 Mixin(只写能力)
python
class RetryMixin:
def retry(self, func, times=3):
for i in range(times):
try:
return func()
except Exception:
if i == times - 1:
raise
2️⃣ 组合进主类
python
class BasePage:
def __init__(self, page):
self.page = page
class LoginPage(BasePage, RetryMixin):
def login(self):
self.retry(lambda: self.page.click("#login"))
📌 Mixin 永远写在 BasePage 后面(Python MRO 规则)
🧪 测试 & Page Object 中的典型 Mixin 用法
✅ 1. 重试能力(最常见)
python
class RetryClickMixin:
def click_with_retry(self, selector):
self.retry(lambda: self.page.click(selector))
✅ 2. 等待 & 稳定性能力
python
class WaitMixin:
def wait_visible(self, selector, timeout=5000):
self.page.wait_for_selector(selector, timeout=timeout)
✅ 3. AI 能力
python
class AILocatorMixin:
def ai_click(self, desc):
ai.action(desc)
python
class ProductPage(BasePage, WaitMixin, AILocatorMixin):
def add_first_product(self):
try:
self.page.click('[data-testid="add"]')
except:
self.ai_click("点击商品列表第一个加入购物车按钮")
👉 AI 是能力,不是主流程
🔥 这点很重要:Mixin ≠ 工具类
❌ 工具类(反模式)
python
Utils.retry_click(page, selector)
问题:
-
上下文丢失
-
不可扩展
-
代码散落
✅ Mixin(有上下文)
python
self.click_with_retry(selector)
📌 Mixin 天然绑定 Page / Driver / Context
🧬 Mixin + Page Object 的推荐结构
python
pages/
├── base_page.py
├── login_page.py
└── product_page.py
mixins/
├── retry_mixin.py
├── wait_mixin.py
├── ai_mixin.py
└── log_mixin.py
python
class ProductPage(
BasePage,
WaitMixin,
RetryMixin,
AILocatorMixin
):
pass
⚠️ Mixin 的 4 个铁律(踩坑预警)
1️⃣ 一个 Mixin 只做一件事
❌ Retry + Log + Assert
✅ RetryMixin / LogMixin / AssertMixin
2️⃣ 不要在 Mixin 里定义 __init__
(除非你真的懂 MRO)
3️⃣ Mixin 不要依赖另一个 Mixin
否则顺序地狱 💣
4️⃣ 不要用 Mixin 表达"是什么"
Mixin 表达的是:
"你能做什么"
🆚 Mixin vs 装饰器(你可能也在纠结)
| 场景 | 用哪个 |
|---|---|
| 横向能力 | ✅ Mixin |
| 单个函数增强 | 装饰器 |
| 动态注入 | 装饰器 |
| Page / Driver 能力 | ✅ Mixin |