Skip to content
📖 Auto 版 TypeScript DeepDive本书目录

设计模式 ​

本章介绍 TypeScript 中常见的设计模式,以及它们如何映射到 Auto。大多数模式 可以直接迁移,但 Auto 的类型系统和模块模型简化了其中几种。

单例 ​

单例模式确保一个类只有一个实例。在 TypeScript 中,经典做法是使用 private 构造函数配合 static getInstance() 方法:

typescript
// TypeScript — 单例类
class Database {
    private static instance: Database;
    private constructor() {}

    static getInstance(): Database {
        if (!Database.instance) {
            Database.instance = new Database();
        }
        return Database.instance;
    }
}

在实践中,TypeScript 开发者更倾向于使用更简单的模块级导出方式—— 模块只会被求值一次,因此其顶层导出天然就是单例:

typescript
// TypeScript — 模块单例(推荐)
export const db = new Database();

Auto 更进一步。在 Auto 中,模块的顶层状态天然就是单例——在整个程序中 共享。不需要私有构造函数或 getInstance() 样板代码:

auto
// Auto — 模块单例(唯一的方式)
var db = Database()

无需任何仪式。模块系统保证了单一实例。

柯里化 ​

柯里化将 f(a, b) => c 转换为 f(a) => f(b) => c,实现偏应用 和干净的函数组合:

typescript
// TypeScript
const add = (x: number) => (y: number) => x + y;
const add5 = add(5);
add5(3);   // 8
add5(10);  // 15

Auto 的语法几乎完全相同——用空格分隔的类型注解替代冒号:

auto
// Auto
let add = (x int) => (y int) => x + y
let add5 = add(5)
add5(3)   // 8
add5(10)  // 15

柯里化在构建可复用的工具函数时非常有用。柯里化的日志函数可以预绑定日志级别:

typescript
const log = (level: string) => (msg: string) =>
    console.log(`[${level}] ${msg}`);
const warn = log("WARN");
warn("disk space low");
auto
let log = (level str) => (msg str) =>
    print("[{level}] {msg}")
let warn = log("WARN")
warn("disk space low")

构建器模式 ​

构建器模式通过链式调用逐步构建复杂对象。两种语言都通过返回 this 或 self 的链式方法来支持这一模式:

typescript
// TypeScript
class QueryBuilder {
    private table = "";
    private conditions: string[] = [];

    from(table: string): this { this.table = table; return this; }
    where(c: string): this { this.conditions.push(c); return this; }
    build(): string {
        const w = this.conditions.length > 0
            ? " WHERE " + this.conditions.join(" AND ") : "";
        return "SELECT * FROM " + this.table + w;
    }
}
const q = new QueryBuilder().from("users").where("age > 18").build();
auto
// Auto
type QueryBuilder {
    var table str
    var conditions []str

    fn from(table str) QueryBuilder { self.table = table; self }
    fn where(c str) QueryBuilder { self.conditions.push(c); self }
    fn build() str {
        let w = if self.conditions.len() > 0 {
            " WHERE " + self.conditions.join(" AND ")
        } else { "" }
        "SELECT * FROM " + self.table + w
    }
}
fn main() {
    let q = QueryBuilder().from("users").where("age > 18").build()
    print(q)
}

该模式在两种语言中完全相同。Auto 的显式 self 返回类型比 TypeScript 的多态 this 更清晰。

类型安全的事件发射器 ​

类型安全的事件发射器提供订阅/发射机制,具有完整的类型安全。每个发射器 由事件数据类型 T 参数化,因此监听器接收正确类型的参数。

Emitter<T> 泛型确保 Emitter<number> 只接受和发射数字。两种语言以相同 方式实现——Auto 只是去掉了分号并使用空格分隔的类型注解。

观察者模式 ​

观察者模式与事件发射器密切相关——订阅者监听被观察对象的状态变更。其实现 与上文的 Emitter<T> 几乎相同,用 subscribe()/set() 替代 on()/emit()。 Auto 的 is 模式匹配还可以在单个处理函数中路由不同的事件类型。在大多数 情况下,事件发射器更受青睐,因为它将事件源与触发状态解耦。

工厂模式 ​

工厂模式在不暴露创建逻辑的情况下创建对象。Auto 使用 type 代替 class,并返回 Result<T> 而非抛出异常:

typescript
// TypeScript — 工厂(错误时抛异常)
interface Shape { area(): number; }
class Circle implements Shape {
    constructor(private r: number) {}
    area(): number { return Math.PI * this.r * this.r; }
}
function createShape(t: string): Shape {
    if (t === "circle") return new Circle(5);
    throw new Error("Unknown: " + t);
}
auto
// Auto — 工厂(返回 Result)
spec Shape { fn area() f64 }
type Circle is Shape {
    radius f64
    fn area() f64 { 3.14159 * self.radius * self.radius }
}
fn createShape(t str) Result<Shape> {
    t is
        "circle" => ok(Circle(5.0))
        _        => err("Unknown: " + t)
}

使用 Result&lt;T&gt; 而非异常使错误路径显式化,并强制调用者在编译期处理失败。

快速参考 ​

概念TypeScriptAuto
单例private constructor + static getInstance()模块顶层状态
柯里化(x: number) =&gt; (y: number) =&gt; ...(x int) =&gt; (y int) =&gt; ...
构建器链式方法返回 this链式方法返回 self
事件发射器class Emitter&lt;T&gt;type Emitter&lt;T&gt;
观察者subscribe() 返回取消订阅函数subscribe() 配合 is 匹配
工厂function 返回 Shape(抛异常)fn 返回 Result&lt;Shape&gt;
错误处理throw new Error(...)Result&lt;T&gt; 配合 err(...)

基于 MIT 许可发布。