Files
structrail-design/.trae/documents/sdk-initialization-patterns.md
skycurtain b67115b50c refactor(array-tracer): 移除 preset 指令并简化类型参数
- 将 preset 功能合并到 create 指令中,简化 API 设计
- 移除 ArrayTracerPresetCommand 类型及相关处理逻辑
- 调整 createArrayTracer 泛型参数以直接接受数组类型
- 更新相关文档以反映新的初始化模式
2026-02-04 13:33:23 +08:00

225 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 多语言 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<T> {
description: string;
array?: T[]; // 可选初始化数据
}
export const createArrayTracer = <T>(options: ArrayTracerOptions<T>) => { ... }
// 调用
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<T> {
// 构造函数 1: 仅描述
public ArrayTracer(String description) {
this(description, null);
}
// 构造函数 2: 描述 + 数据
public ArrayTracer(String description, List<T> data) {
// ... implementation
}
}
// 调用
var t1 = new ArrayTracer<Integer>("Empty");
var t2 = new ArrayTracer<Integer>("My Array", Arrays.asList(1, 2, 3));
```
### 4. C++ (Overloading & Initializer List)
利用 `std::initializer_list` 支持花括号初始化,语法极其简洁。
```cpp
template <typename T>
class ArrayTracer {
public:
// 基础构造
ArrayTracer(std::string description) { ... }
// 带数据构造 (支持 vector)
ArrayTracer(std::string description, const std::vector<T>& data) { ... }
// 带数据构造 (支持 {1,2,3} 字面量)
ArrayTracer(std::string description, std::initializer_list<T> data) { ... }
};
// 调用
ArrayTracer<int> t1("Empty");
ArrayTracer<int> 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<i32>) -> Self { ... }
pub fn build(self) -> ArrayTracer { ... }
}
// 调用
let t = ArrayTracer::builder("My Array")
.with_data(vec![1, 2, 3])
.build();
```
### 7. C# (Optional Arguments)
类似于 TypeScript 和 KotlinC# 支持命名参数和默认值。
```csharp
public class ArrayTracer<T> {
public ArrayTracer(string description, IEnumerable<T> data = null) {
// ...
}
}
// 调用
var t1 = new ArrayTracer<int>("Empty");
var t2 = new ArrayTracer<int>("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 使用体验。这不仅降低了用户的学习成本,也使得代码更加紧凑和易读。