# 多语言 SDK 初始化设计规范 ## 背景 为了简化 SDK 的使用流程并统一 API 设计体验,我们决定将 Tracer 的初始化数据(Initial Data)合并到创建(Create)阶段。这意味着用户在实例化 Tracer 时,可以直接传入初始数据,而无需单独调用 `preset` 方法。 这一设计模式(Construct as Initialize)在大多数现代编程语言中都有成熟的最佳实践。本文档旨在为不同语言的 SDK 实现提供具体的代码范式参考。 ## 核心原则 1. **优先使用构造函数参数**:如果语言支持(如 Python, Kotlin, Swift),优先使用带默认值的命名参数。 2. **利用语言特性**: - **重载 (Overloading)**:适用于 Java, C++, C#。 - **配置对象 (Options Object)**:适用于 TS, JS, Lua。 - **Builder / Functional Options**:适用于 Go, Rust。 3. **保持协议底层一致**:无论上层 API 如何设计,底层生成的 `create` 指令 JSON 必须包含 `array` (或对应数据字段) 参数。 --- ## 各语言实现参考 ### 1. TypeScript / JavaScript (当前基准) 利用接口(Interface)定义配置对象,简洁且扩展性强。 ```typescript // 定义 interface ArrayTracerOptions { description: string; array?: T[]; // 可选初始化数据 } export const createArrayTracer = (options: ArrayTracerOptions) => { ... } // 调用 const t1 = createArrayTracer({ description: "Empty" }); const t2 = createArrayTracer({ description: "My Array", array: [1, 2, 3] }); ``` ### 2. Python (Keyword Arguments) 利用 `**kwargs` 或显式关键字参数,非常符合 Pythonic 风格。 ```python class ArrayTracer: def __init__(self, description: str, data: list = None): self.description = description if data: self._emit_create(data) # 调用 t1 = ArrayTracer(description="Empty") t2 = ArrayTracer(description="My Array", data=[1, 2, 3]) ``` ### 3. Java (Constructor Overloading) 利用构造函数重载提供多种初始化路径。 ```java public class ArrayTracer { // 构造函数 1: 仅描述 public ArrayTracer(String description) { this(description, null); } // 构造函数 2: 描述 + 数据 public ArrayTracer(String description, List data) { // ... implementation } } // 调用 var t1 = new ArrayTracer("Empty"); var t2 = new ArrayTracer("My Array", Arrays.asList(1, 2, 3)); ``` ### 4. C++ (Overloading & Initializer List) 利用 `std::initializer_list` 支持花括号初始化,语法极其简洁。 ```cpp template class ArrayTracer { public: // 基础构造 ArrayTracer(std::string description) { ... } // 带数据构造 (支持 vector) ArrayTracer(std::string description, const std::vector& data) { ... } // 带数据构造 (支持 {1,2,3} 字面量) ArrayTracer(std::string description, std::initializer_list data) { ... } }; // 调用 ArrayTracer t1("Empty"); ArrayTracer t2("My Array", {1, 2, 3}); ``` ### 5. Go (Functional Options Pattern) Go 社区处理复杂构造参数的标准模式。 ```go type Option func(*ArrayTracer) func WithData(data []interface{}) Option { return func(t *ArrayTracer) { t.initialData = data } } func NewArrayTracer(desc string, opts ...Option) *ArrayTracer { t := &ArrayTracer{Description: desc} for _, opt := range opts { opt(t) } return t } // 调用 t1 := NewArrayTracer("Empty") t2 := NewArrayTracer("My Array", WithData([]interface{}{1, 2, 3})) ``` ### 6. Rust (Builder Pattern) 利用 Builder 模式处理构造参数,保证类型安全和可读性。 ```rust struct ArrayTracerBuilder { ... } impl ArrayTracer { pub fn builder(description: &str) -> ArrayTracerBuilder { ... } } impl ArrayTracerBuilder { pub fn with_data(mut self, data: Vec) -> Self { ... } pub fn build(self) -> ArrayTracer { ... } } // 调用 let t = ArrayTracer::builder("My Array") .with_data(vec![1, 2, 3]) .build(); ``` ### 7. C# (Optional Arguments) 类似于 TypeScript 和 Kotlin,C# 支持命名参数和默认值。 ```csharp public class ArrayTracer { public ArrayTracer(string description, IEnumerable data = null) { // ... } } // 调用 var t1 = new ArrayTracer("Empty"); var t2 = new ArrayTracer("My Array", data: new[] { 1, 2, 3 }); ``` ### 8. C 语言 (Special Case) C 语言不支持重载,且缺乏自省能力,因此建议提供两种创建模式: **方案 A: 基础数据类型 (使用宏或特定后缀)** 对于 `int`, `float` 等基础类型,提供专用函数。 ```c // 基础创建 tracer_t* tracer_create_array(const char* desc); // 带数据创建 (Explicit is better than implicit) tracer_t* tracer_create_array_with_data(const char* desc, void* data, size_t len); // 调用 tracer_t* t1 = tracer_create_array("Empty"); int nums[] = {1, 2, 3}; tracer_t* t2 = tracer_create_array_with_data("My Array", nums, 3); ``` **方案 B: 自定义结构体 (Callback 模式)** 对于用户自定义的 `struct`,采用类似 `qsort` 的回调函数模式,让用户提供序列化逻辑。 ```c // 定义序列化回调: 将 elem 转换为 JSON 字符串写入 buffer typedef void (*serializer_func)(const void* elem, char* buffer); /** * @param serializer 用户提供的序列化函数 */ tracer_t* tracer_create_array_custom( const char* desc, const void* data, size_t len, size_t elem_size, serializer_func serializer ); // 用户代码示例 typedef struct { int x; int y; } Point; // 用户编写序列化逻辑 void point_serializer(const void* elem, char* buffer) { const Point* p = (const Point*)elem; sprintf(buffer, "{\"x\":%d,\"y\":%d}", p->x, p->y); } // 调用 Point pts[] = {{1,2}, {3,4}}; tracer_t* t = tracer_create_array_custom("Points", pts, 2, sizeof(Point), point_serializer); ``` --- ## 总结 通过统一采用**“构造即初始化”**的设计模式,我们能够在几乎所有主流编程语言中提供一致、简洁且符合语言习惯(Idiomatic)的 SDK 使用体验。这不仅降低了用户的学习成本,也使得代码更加紧凑和易读。