Skip to Content
🎲 欢迎使用 RandBox - 功能强大的 JavaScript 随机数据生成库! 了解详情
博客从零开始打造 RandBox:一个强大的 JavaScript 随机数据生成库(2/5)- 技术架构与核心实现

从零开始打造 RandBox:一个强大的 JavaScript 随机数据生成库(2/5)- 技术架构与核心实现

前言

在上一篇文章中,我们探讨了 RandBox 项目的起源和整体规划。今天,我将深入技术细节,分享 RandBox 核心架构的设计思路和关键实现。从随机数生成器的选择到 TypeScript 类型系统的设计,每一个技术决策都承载着对开发体验和性能的深度思考。

核心架构设计

分层架构模式

RandBox 采用经典的分层架构,确保代码的可维护性和扩展性:

┌─────────────────────────────────────────┐ │ API Layer (用户接口层) │ ├─────────────────────────────────────────┤ │ Module Layer (模块层) │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ Person │ │Location │ │Finance │ ...│ │ └─────────┘ └─────────┘ └─────────┘ │ ├─────────────────────────────────────────┤ │ Core Layer (核心层) │ │ 随机数生成器 | 工具函数 | 类型定义 │ ├─────────────────────────────────────────┤ │ Runtime Layer (运行时层) │ │ Node.js | Browser | 小程序 │ └─────────────────────────────────────────┘

核心模块详解

1. Core 模块 - 基础设施

Core 模块是整个 RandBox 的基石,提供基础的随机数生成能力和工具函数:

// src/core.ts 核心类设计 export class RandBox { private mt: MersenneTwister; private seed: string | number | undefined; constructor(seed?: string | number) { this.seed = seed; this.mt = new MersenneTwister(this.getSeedValue(seed)); } // 核心随机数生成方法 random(): number { return this.mt.random(); } // 工具方法:范围检查 testRange(test: boolean, message: string): void { if (test) { throw new RangeError(message); } } // 工具方法:初始化选项 initOptions<T>(options: T | undefined, defaultOptions: T): T { return { ...defaultOptions, ...options }; } }

为什么选择 Mersenne Twister?

  1. 高质量随机性:周期长达 2^19937-1,几乎无重复
  2. 性能优秀:计算效率高,适合大量数据生成
  3. 可预测性:支持种子设置,便于测试和调试
  4. 广泛认可:被众多编程语言和库采用

2. 类型系统设计

TypeScript 类型系统是 RandBox 的核心优势之一,我们设计了完整的类型定义:

// src/types.ts 类型定义 export interface RandBoxOptions { seed?: string | number; } // 基础数据类型的选项接口 export interface IntegerOptions { min?: number; max?: number; exclude?: number[]; } export interface StringOptions { length?: number; pool?: string; alpha?: boolean; numeric?: boolean; symbols?: boolean; casing?: 'lower' | 'upper' | 'mixed'; } // 复杂类型的选项接口 export interface PersonOptions { nationality?: 'zh' | 'en' | 'fr' | 'de'; gender?: 'male' | 'female' | 'mixed'; middle_initial?: boolean; prefix?: boolean; suffix?: boolean; } // 函数重载支持 export interface RandBoxInstance { // integer 方法的多种调用方式 integer(): number; integer(max: number): number; integer(min: number, max: number): number; integer(options: IntegerOptions): number; // 其他方法... name(options?: PersonOptions): string; email(options?: EmailOptions): string; }

类型设计原则:

  1. 渐进式复杂度:从简单调用到复杂配置的平滑过渡
  2. 智能推导:TypeScript 自动推导返回类型
  3. 可扩展性:接口设计便于后续功能扩展

3. 模块化设计实现

每个功能模块都独立开发,通过统一的模式进行组织:

// src/person.ts 示例模块 import { RandBox } from './core'; // 姓名生成函数 export function name(this: RandBox, options?: PersonOptions): string { const opts = this.initOptions(options, { nationality: 'zh', gender: 'mixed', middle_initial: false }); const firstNames = DATA_SETS.firstNames[opts.nationality][opts.gender]; const lastNames = DATA_SETS.lastNames[opts.nationality]; const firstName = this.pickone(firstNames); const lastName = this.pickone(lastNames); return opts.nationality === 'zh' ? `${lastName}${firstName}` : `${firstName} ${lastName}`; } // 电子邮件生成函数 export function email(this: RandBox, options?: EmailOptions): string { const opts = this.initOptions(options, { domain: null, length: null }); const username = opts.length ? this.string({ length: opts.length, casing: 'lower' }) : this.first().toLowerCase(); const domain = opts.domain || this.pickone(COMMON_DOMAINS); return `${username}@${domain}`; } // 导出所有函数 export const personFunctions = { name, email, age, birthday, gender };

数据管理策略

1. 本地化数据组织

RandBox 内置了丰富的本地化数据,支持多种语言和地区:

// src/datasets.ts 数据集组织 export const DATA_SETS = { firstNames: { zh: { male: ['伟', '强', '磊', '军', '洋', '勇', '杰', '华'], female: ['秀英', '桂英', '秀兰', '玉兰', '桂兰', '秀珍', '丽'], mixed: [] // 合并男女姓名 }, en: { male: ['James', 'John', 'Robert', 'Michael', 'William'], female: ['Mary', 'Patricia', 'Jennifer', 'Linda', 'Elizabeth'] } }, lastNames: { zh: ['王', '李', '张', '刘', '陈', '杨', '赵', '黄', '周', '吴'], en: ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones'] }, // 地址数据 addresses: { zh: { provinces: ['北京市', '上海市', '广东省', '江苏省'], cities: { '北京市': ['朝阳区', '海淀区', '西城区', '东城区'], '上海市': ['浦东新区', '黄浦区', '徐汇区', '长宁区'] } } }, // 更多数据集... };

2. 智能缓存机制

为了提高性能,RandBox 实现了智能缓存:

class DataCache { private cache = new Map<string, any>(); private maxSize = 1000; get<T>(key: string, generator: () => T): T { if (this.cache.has(key)) { return this.cache.get(key); } const value = generator(); if (this.cache.size >= this.maxSize) { // LRU 淘汰策略 const firstKey = this.cache.keys().next().value; this.cache.delete(firstKey); } this.cache.set(key, value); return value; } }

算法核心实现

1. Mersenne Twister 实现

class MersenneTwister { private mt: number[] = new Array(624); private mti: number = 625; constructor(seed?: number) { this.init_genrand(seed || Date.now()); } private init_genrand(s: number): void { this.mt[0] = s >>> 0; for (this.mti = 1; this.mti < 624; this.mti++) { s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30); this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253) + this.mti; this.mt[this.mti] >>>= 0; } } genrand_int32(): number { let y: number; const mag01 = [0x0, 0x9908b0df]; if (this.mti >= 624) { // 生成新的随机数序列 let kk: number; for (kk = 0; kk < 227; kk++) { y = (this.mt[kk] & 0x80000000) | (this.mt[kk + 1] & 0x7fffffff); this.mt[kk] = this.mt[kk + 397] ^ (y >>> 1) ^ mag01[y & 0x1]; } // ... 更多实现细节 this.mti = 0; } y = this.mt[this.mti++]; // Tempering y ^= y >>> 11; y ^= (y << 7) & 0x9d2c5680; y ^= (y << 15) & 0xefc60000; y ^= y >>> 18; return y >>> 0; } random(): number { return this.genrand_int32() * (1.0 / 4294967296.0); } }

2. 高级随机算法

正态分布实现(Box-Muller 变换)

export function normal(this: RandBox, mean = 0, deviation = 1): number { // Box-Muller 变换生成正态分布 if (this.normal_cache !== null) { const cached = this.normal_cache; this.normal_cache = null; return cached * deviation + mean; } const u1 = this.random(); const u2 = this.random(); const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); const z1 = Math.sqrt(-2 * Math.log(u1)) * Math.sin(2 * Math.PI * u2); this.normal_cache = z1; return z0 * deviation + mean; }

加权随机选择实现

export function weighted<T>( this: RandBox, array: T[], weights: number[] ): T { if (array.length !== weights.length) { throw new Error('Array and weights must have the same length'); } // 计算累积权重 const totalWeight = weights.reduce((sum, weight) => sum + weight, 0); const cumulativeWeights: number[] = []; let sum = 0; for (let i = 0; i < weights.length; i++) { sum += weights[i] / totalWeight; cumulativeWeights[i] = sum; } // 随机选择 const random = this.random(); for (let i = 0; i < cumulativeWeights.length; i++) { if (random <= cumulativeWeights[i]) { return array[i]; } } return array[array.length - 1]; }

构建与优化

1. Rollup 配置优化

// rollup.config.js import typescript from '@rollup/plugin-typescript'; import { terser } from 'rollup-plugin-terser'; import resolve from '@rollup/plugin-node-resolve'; export default { input: 'src/index.ts', output: [ // ESM 格式(支持 Tree Shaking) { file: 'dist/index.esm.mjs', format: 'es', sourcemap: true }, // CommonJS 格式 { file: 'dist/index.cjs', format: 'cjs', sourcemap: true }, // UMD 格式(浏览器直接使用) { file: 'dist/index.umd.js', format: 'umd', name: 'RandBox', sourcemap: true } ], plugins: [ resolve(), typescript({ tsconfig: './tsconfig.json', declaration: true, declarationDir: 'dist' }), terser() // 代码压缩 ], // 分包配置,支持按需引入 external: id => !id.startsWith('.') && !id.startsWith('/'), // 多入口配置 input: { index: 'src/index.ts', core: 'src/core.ts', person: 'src/person.ts', location: 'src/location.ts', // ... 其他模块 } };

2. Tree Shaking 优化

为了实现最佳的 Tree Shaking 效果,我们采用了特殊的导出策略:

// src/index.ts 主入口 export { RandBox as default } from './core'; export * from './types'; // 模块化导出 export * as basics from './basics'; export * as person from './person'; export * as location from './location'; // ... 其他模块 // src/person.ts 模块导出 export const name = function(this: RandBox, options?: PersonOptions): string { // 实现 }; export const email = function(this: RandBox, options?: EmailOptions): string { // 实现 }; // 批量导出(便于主类集成) export const personFunctions = { name, email, age, birthday };

这样的设计允许用户以不同方式使用:

// 方式1:完整引入 import RandBox from 'randbox'; const randBox = new RandBox(); // 方式2:按模块引入 import * as person from 'randbox/dist/person'; console.log(person.name()); // 方式3:按需引入 import { name, email } from 'randbox/dist/person';

性能优化策略

1. 懒加载数据集

class LazyDataSet<T> { private _data: T | null = null; private loader: () => T; constructor(loader: () => T) { this.loader = loader; } get data(): T { if (this._data === null) { this._data = this.loader(); } return this._data; } } // 使用示例 const CHINESE_NAMES = new LazyDataSet(() => require('./datasets/chinese-names.json') );

2. 内存池优化

class ObjectPool<T> { private pool: T[] = []; private createFn: () => T; private resetFn: (obj: T) => void; constructor(createFn: () => T, resetFn: (obj: T) => void) { this.createFn = createFn; this.resetFn = resetFn; } get(): T { if (this.pool.length > 0) { return this.pool.pop()!; } return this.createFn(); } release(obj: T): void { this.resetFn(obj); this.pool.push(obj); } }

错误处理与调试

1. 友好的错误信息

export class RandBoxError extends Error { constructor(message: string, public code: string) { super(message); this.name = 'RandBoxError'; } } export class ValidationError extends RandBoxError { constructor(parameter: string, value: any, expected: string) { super( `Invalid parameter "${parameter}": expected ${expected}, got ${typeof value}`, 'VALIDATION_ERROR' ); } } // 使用示例 export function integer(this: RandBox, min?: number, max?: number): number { if (min !== undefined && typeof min !== 'number') { throw new ValidationError('min', min, 'number'); } if (max !== undefined && typeof max !== 'number') { throw new ValidationError('max', max, 'number'); } if (min !== undefined && max !== undefined && min > max) { throw new RandBoxError( `Minimum value (${min}) cannot be greater than maximum value (${max})`, 'INVALID_RANGE' ); } // 实现逻辑... }

2. 调试支持

export class RandBox { private debugMode = false; private callHistory: Array<{ method: string; args: any[]; result: any }> = []; enableDebug(): void { this.debugMode = true; } getCallHistory(): ReadonlyArray<any> { return this.callHistory; } private logCall(method: string, args: any[], result: any): void { if (this.debugMode) { this.callHistory.push({ method, args, result }); console.log(`RandBox.${method}(${JSON.stringify(args)}) -> ${result}`); } } }

下期预告

在下一篇文章中,我将详细介绍如何实现 RandBox 的丰富功能模块,包括:

  • 各个专业领域数据生成的实现细节
  • 复杂算法的应用(如地理坐标生成、信用卡号验证等)
  • 本地化数据的处理与优化
  • 高级功能的实现技巧

敬请期待《从零开始打造 RandBox(3/5)- 功能模块深度实现》!


关于 RandBox

🏠 官网: https://randbox.top  📦 GitHub: https://github.com/027xiguapi/randbox  📚 文档: https://randbox.top/zh/docs 

如果这个项目对你有帮助,欢迎给我们一个 ⭐ Star!

最后更新于: