mcpField
D
design-patterns

design-patterns

github.com/waybarrios开发54952 次安装6 天前更新
代码仓库

关于 design-patterns

design-patterns 是一项设计模式参考技能,涵盖 Rust、TypeScript/React 和 Django/Python。它根据具体情境比较方案与取舍,并提供反模式指导。

主要功能

  1. 01涵盖 Rust、TypeScript/React 和 Django/Python
  2. 02说明模式的适用与不适用情境
  3. 03比较方案及其取舍
  4. 04提供反模式目录与选择步骤

适用场景

  1. 01为具体设计问题选择模式
  2. 02按项目约束比较实现方案
  3. 03检查代码中的常见反模式

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/waybarrios/opencode-power-pack --skill design-patterns

安装后在 Claude Code 中输入/design-patterns确认已加载。

详细介绍

设计模式

针对常见技术栈量身定制的模式建议。每条建议都包含适用场景、不适用场景和权衡取舍。

快速入门

选择模式
  1. 明确问题: 你要解决什么设计难题?
  2. 考虑上下文: 使用什么语言?规模如何?变更频率有多高?
  3. 评估选项: 列出 2-3 种候选模式及其权衡取舍
  4. 给出建议: 选择最适合当前具体上下文的模式(而不是一般意义上的“最佳模式”)

黄金法则: 模式是工具,不是目标。使用能解决问题的最简单模式。如果没有合适的模式,普通函数或结构体就可以。


Rust 模式

Newtype 模式

封装基础类型,增加类型安全性和领域含义。

struct UserId(u64);
struct OrderId(u64);

// Now the compiler prevents mixing up UserId and OrderId
fn get_order(user: UserId, order: OrderId) -> Order { ... }

适用场景: 两个值的底层类型相同,但含义不同。 不适用场景: 仅使用一次,类型别名就足够。

Builder 模式

逐步构造复杂对象。

let config = ServerConfig::builder()
    .host("localhost")
    .port(8080)
    .max_connections(100)
    .build()?;

适用场景: 字段众多且包含许多可选字段的结构体,或构造逻辑复杂的对象。 不适用场景: 只有 1-3 个必需字段的结构体——直接使用 new()。

Typestate 模式

在类型系统中编码状态转换,让无效状态无法表示。

struct Connection<S: State> { /* ... */ state: PhantomData<S> }
struct Disconnected;
struct Connected;
struct Authenticated;

impl Connection<Disconnected> {
    fn connect(self) -> Result<Connection<Connected>> { ... }
}
impl Connection<Connected> {
    fn authenticate(self, creds: &Credentials) -> Result<Connection<Authenticated>> { ... }
}
impl Connection<Authenticated> {
    fn query(&self, sql: &str) -> Result<Rows> { ... }
}
// Can't call query() on a Disconnected connection — compile error

适用场景: 状态转换明确的协议(连接、工作流、解析阶段)。 不适用场景: 简单的开关状态——使用布尔值或枚举更清晰。

Trait 对象与泛型
方式分发方式二进制大小灵活性
impl Trait(泛型)静态(单态化)较大(每种类型一份)编译时已知
dyn Trait(Trait 对象)动态(虚函数表)较小(一份)运行时可扩展

使用泛型的场景: 性能很重要、类型在编译时已知,或需要零成本抽象。 使用 Trait 对象的场景: 需要异构集合、插件系统,或类型集合不固定。

错误处理模式
模式适用场景Crate
thiserror库错误——结构化且包含具体变体thiserror
anyhow应用错误——上下文丰富,便于快速传播anyhow
自定义枚举调用方需要进行穷尽匹配仅使用 std

经验法则: 库使用 thiserror(调用方需要匹配错误)。应用使用 anyhow(调用方需要上下文)。


TypeScript / React 模式

复合组件

通过共享上下文隐式协作的组件。

<Select>
  <Select.Trigger>Choose a fruit</Select.Trigger>
  <Select.Options>
    <Select.Option value="apple">Apple</Select.Option>
    <Select.Option value="banana">Banana</Select.Option>
  </Select.Options>
</Select>

适用场景: 包含多个相关部分的复杂 UI 组件(菜单、折叠面板、标签页)。 不适用场景: 只有 1-2 个元素的简单组件。

自定义 Hook 组合

将行为提取并组合为可复用的 Hook。

function useDebounce<T>(value: T, delay: number): T { ... }
function usePagination(items: Item[], pageSize: number) { ... }
function useLocalStorage<T>(key: string, initial: T) { ... }

适用场景: 组件间共享的有状态逻辑,或组件内部复杂的状态管理。 不适用场景: 不会重复使用的一次性逻辑。

判别联合类型

使用 TypeScript 的联合类型进行类型安全的状态建模。

type AsyncState<T> =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: T }
  | { status: "error"; error: Error };

// Exhaustive switch — TypeScript ensures all cases handled
function render(state: AsyncState<User>) {
  switch (state.status) {
    case "idle": return <Placeholder />;
    case "loading": return <Spinner />;
    case "success": return <UserCard user={state.data} />;
    case "error": return <ErrorBanner error={state.error} />;
  }
}

适用场景: 状态机、API 响应状态、表单状态,以及任何包含不同模式的场景。 不适用场景: 简单开关状态使用布尔标记即可。

状态管理决策树
  1. UI 局部状态? -> useState / useReducer
  2. 兄弟组件间共享? -> 将状态提升到共同的父组件
  3. 远距离组件间共享? -> React Context
  4. 状态逻辑复杂? -> useReducer + Context
  5. 服务端状态(API 数据)? -> TanStack Query / SWR
  6. 全局应用状态? -> Zustand / Jotai(新项目优先于 Redux)

Django / Python 模式

服务层

将业务逻辑与视图和模型分离。

# services/order_service.py
class OrderService:
    @staticmethod
    def create_order(user: User, items: list[CartItem]) -> Order:
        """Business logic lives here, not in the view."""
        order = Order.objects.create(user=user, total=calculate_total(items))
        OrderItem.objects.bulk_create([...])
        send_confirmation_email(user, order)
        return order

适用场景: 涉及多个模型、外部调用或复杂验证的业务逻辑。 不适用场景: 除 Django 内置验证外没有其他业务规则的简单 CRUD。

仓储模式(QuerySet 抽象)

自定义管理器和查询集,用于封装查询逻辑。

class PublishedManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(status="published")

class Article(models.Model):
    objects = models.Manager()  # Default
    published = PublishedManager()  # Article.published.all()

适用场景: 复杂或可复用的查询逻辑、特定领域的筛选。 不适用场景: 一次性查询或简单筛选。

信号与显式调用
方式优点缺点
Django 信号解耦,可跨应用使用控制流隐蔽,难以调试,存在顺序问题
显式调用清晰、易于调试和测试模块之间存在耦合

经验法则: 对于真正横切的关注点(审计日志记录、缓存失效),使用信号。对于需要理解并测试流程的业务关键逻辑,使用显式调用。


反模式(适用于所有技术栈)

反模式问题改进方法
过早抽象尚未看到模式重复就进行抽象等出现 3 个实例后再提取
继承优于组合继承层级过深,基类脆弱优先使用组合(特征、钩子、混入)
上帝对象一个类或模块包揽所有工作按职责拆分(SRP)
霰弹式修改一处改动需要编辑许多文件将相关代码归到一起
功能迷恋某个函数使用其他类的数据多于自身数据将该函数移到它所迷恋的类中
臆测性通用化为可能永远不会出现的用例构建功能YAGNI——立足当前需求构建,必要时再重构
金锤子所有问题都使用同一种模式或工具根据任务选择合适的工具

模式选择指南

当被问到“我该使用哪种模式?”时:

  1. 描述问题(而不是你认为适用的模式)
  2. 明确约束条件(性能、可扩展性、团队规模、时间安排)
  3. 提供 2-3 种方案并说明权衡
  4. 推荐一种方案并给出明确理由
  5. 说明何时重新评估——“如果 X 发生变化,就重新考虑 Y”

集成

交叉参考此资源包的 code-architect 技能,以评估结构和架构;参考 code-quality,了解促使重构并采用某种模式的复杂度阈值。

评论

支持 Markdown