×
¥
查看详情
🔥 会员专享 文生代码 API

类模块结构生成

👁️ 500 次查看
📅 Nov 19, 2025
💡 核心价值: 本提示词可根据用户需求生成完整类结构,包含关键属性、方法及参数与返回类型说明,支持前端组件化开发与面向对象建模,提升类设计效率与代码可维护性。

🎯 可自定义参数(5个)

编程语言
用于编写类结构的编程语言
类名称
需要设计的类名称
类职责描述
描述该类需要管理的业务功能范围
属性信息
包含属性名称、类型及详细说明的信息
方法信息
包含方法名称、参数及返回类型说明的信息

🎨 效果示例

下面给出一个可用于 React/Vue/Svelte 等组件化开发的可复用 FormValidator 类结构实现。其具备字段/表单级校验、同步与异步混合规则、防抖控制、消息本地化与可插拔消息格式化、解耦的事件通知、动态增删规则、跨字段依赖与远程唯一性校验等能力。

代码(TypeScript):

// Supporting types
export type Locale = 'en' | 'zh' | 'es';

export type ValidationRule = {
  name: string;
  test: (value: unknown, ctx?: Record<string, unknown>) => boolean | Promise<boolean>;
  message?: string;
  severity?: 'error' | 'warning';
};

export type ValidationResult = {
  valid: boolean;
  errors: string[];
};

export interface EventEmitter {
  on(event: string, cb: (payload?: unknown) => void): void;
  off(event: string, cb: (payload?: unknown) => void): void;
  emit(event: string, payload?: unknown): void;
}

type MessageFormatter = (
  template: string,
  params?: Record<string, unknown>,
  locale?: Locale
) => string;

type Values = Record<string, unknown>;
type Ctx = Record<string, unknown>;

// Simple default emitter (decoupled from any UI framework)
class SimpleEmitter implements EventEmitter {
  private listeners = new Map<string, Set<(payload?: unknown) => void>>();
  on(event: string, cb: (payload?: unknown) => void) {
    if (!this.listeners.has(event)) this.listeners.set(event, new Set());
    this.listeners.get(event)!.add(cb);
  }
  off(event: string, cb: (payload?: unknown) => void) {
    this.listeners.get(event)?.delete(cb);
  }
  emit(event: string, payload?: unknown) {
    this.listeners.get(event)?.forEach((cb) => {
      try {
        cb(payload);
      } catch {
        /* swallow */
      }
    });
  }
}

export class FormValidator {
  // properties
  public rules: Map<string, ValidationRule[]> = new Map();
  public errors: Map<string, string[]> = new Map();
  public locale: Locale = 'en';
  public messages: Record<string, Record<string, string>>;
  public debounceMs: number = 250;
  public emitter: EventEmitter;
  public disposed: boolean = false;

  // pluggable message formatter
  private formatter: MessageFormatter;

  // internal state for debounce/coalescing
  private fieldTimers: Map<string, ReturnType<typeof setTimeout>> = new Map();
  private fieldLatestArgs: Map<string, { value: unknown; context?: Ctx }> = new Map();
  private fieldPending: Map<
    string,
    { promise: Promise<ValidationResult>; resolve: (r: ValidationResult) => void }
  > = new Map();

  constructor(options?: {
    locale?: Locale;
    messages?: Record<Locale, Record<string, string>>;
    debounceMs?: number;
    emitter?: EventEmitter;
    formatter?: MessageFormatter;
  }) {
    this.locale = options?.locale ?? 'en';
    this.debounceMs = options?.debounceMs ?? 250;
    this.emitter = options?.emitter ?? new SimpleEmitter();
    this.messages = {
      en: {
        required: 'This field is required.',
        match: 'Values do not match.',
        unique: 'This value is already taken.',
        minLength: 'Value is too short.',
        maxLength: 'Value is too long.',
        pattern: 'Invalid format.',
        exception: 'Validation failed',
      },
      zh: {
        required: '该字段为必填项。',
        match: '两次输入不一致。',
        unique: '该值已被占用。',
        minLength: '输入长度过短。',
        maxLength: '输入长度过长。',
        pattern: '格式不正确。',
        exception: '校验失败',
      },
      es: {
        required: 'Este campo es obligatorio.',
        match: 'Los valores no coinciden.',
        unique: 'Este valor ya está en uso.',
        minLength: 'El valor es demasiado corto.',
        maxLength: 'El valor es demasiado largo.',
        pattern: 'Formato inválido.',
        exception: 'Falló la validación',
      },
      ...(options?.messages ?? {}),
    };

    // 默认的消息格式化器:简单的 {key} 插值
    this.formatter =
      options?.formatter ??
      ((template: string, params?: Record<string, unknown>) => {
        if (!params) return template;
        return template.replace(/\{(\w+)\}/g, (_, k) =>
          params[k] !== undefined ? String(params[k]) : `{${k}}`
        );
      });
  }

  // methods

  /**
   * 为指定字段添加规则,支持批量和前置插入。
   * @param field 字段名
   * @param rule 单条或多条规则
   * @param options { prepend?: boolean } - 是否前置插入
   */
  public addRule(
    field: string,
    rule: ValidationRule | ValidationRule[],
    options?: { prepend?: boolean }
  ): void {
    this.ensureNotDisposed();
    const list = this.rules.get(field) ?? [];
    const incoming = Array.isArray(rule) ? rule : [rule];
    if (options?.prepend) {
      this.rules.set(field, [...incoming, ...list]);
    } else {
      this.rules.set(field, [...list, ...incoming]);
    }
  }

  /**
   * 移除字段的指定规则或全部规则,返回移除数量。
   * @param field 字段名
   * @param ruleName 可选,规则名称,不传则移除该字段全部规则
   */
  public removeRule(field: string, ruleName?: string): number {
    this.ensureNotDisposed();
    const list = this.rules.get(field);
    if (!list || list.length === 0) return 0;
    if (!ruleName) {
      const count = list.length;
      this.rules.delete(field);
      return count;
    }
    const remain = list.filter((r) => r.name !== ruleName);
    const removed = list.length - remain.length;
    if (remain.length > 0) this.rules.set(field, remain);
    else this.rules.delete(field);
    return removed;
  }

  /**
   * 校验单个字段。对包含异步规则的字段,会进行防抖合并:短时间多次调用将合并为一次最终执行,
   * 结果以“最后一次调用的最新值”为准(last-call-wins)。
   * @param field 字段名
   * @param value 当前字段值
   * @param context 额外上下文(可放入全部表单值以支持跨字段校验)
   * @returns Promise<ValidationResult>
   */
  public validateField(
    field: string,
    value: unknown,
    context?: Ctx
  ): Promise<ValidationResult> {
    this.ensureNotDisposed();
    const rules = this.rules.get(field) ?? [];
    if (rules.length === 0) {
      // 无规则则视为通过并清空错误
      this.errors.delete(field);
      const res: ValidationResult = { valid: true, errors: [] };
      this.emitter.emit('validated', {
        scope: 'field',
        field,
        ...res,
        warnings: [],
      });
      return Promise.resolve(res);
    }

    // 检测是否包含异步规则(粗略检查 async function)
    const hasAsync = rules.some((r) => r.test && r.test.constructor.name === 'AsyncFunction');

    // 合并 context 与默认参数
    const paramsBase = { field, value, ...(context ?? {}) };

    const runAll = async (
      v: unknown,
      ctx?: Ctx
    ): Promise<{ errors: string[]; warnings: string[] }> => {
      const errors: string[] = [];
      const warnings: string[] = [];
      for (const rule of rules) {
        try {
          const ok = await rule.test(v, ctx);
          if (!ok) {
            const template =
              rule.message ??
              this.messages[this.locale]?.[rule.name] ??
              this.messages['en']?.[rule.name] ??
              'Invalid.';
            const msg = this.formatter(template, { ...paramsBase, value: v }, this.locale);
            if (rule.severity === 'warning') warnings.push(msg);
            else errors.push(msg);
          }
        } catch (e) {
          const tmpl = this.messages[this.locale]?.['exception'] ?? 'Validation failed';
          const msg = `${tmpl}${(e as Error)?.message ? `: ${(e as Error).message}` : ''}`;
          errors.push(msg);
          this.emitter.emit('error', { scope: 'field', field, error: e });
        }
      }
      return { errors, warnings };
    };

    // 若全为同步规则,立即执行
    if (!hasAsync || this.debounceMs <= 0) {
      return runAll(value, context).then(({ errors, warnings }) => {
        this.setFieldErrors(field, errors);
        const res: ValidationResult = { valid: errors.length === 0, errors };
        this.emitter.emit('validated', { scope: 'field', field, ...res, warnings });
        return res;
      });
    }

    // 对包含异步规则的字段进行防抖合并
    // 记录最新值与上下文
    this.fieldLatestArgs.set(field, { value, context });

    // 复用 pending promise(多次频繁调用返回同一 promise,最终以最后一次值为准)
    if (!this.fieldPending.has(field)) {
      let resolver!: (r: ValidationResult) => void;
      const promise = new Promise<ValidationResult>((resolve) => {
        resolver = resolve;
      });
      this.fieldPending.set(field, { promise, resolve: resolver });
    }

    // 重置防抖计时器
    const existingTimer = this.fieldTimers.get(field);
    if (existingTimer) clearTimeout(existingTimer);

    const timer = setTimeout(async () => {
      // 取最后一次传入的值与上下文
      const latest = this.fieldLatestArgs.get(field);
      const latestVal = latest?.value;
      const latestCtx = latest?.context;
      const { errors, warnings } = await runAll(latestVal, latestCtx);
      this.setFieldErrors(field, errors);
      const res: ValidationResult = { valid: errors.length === 0, errors };
      this.emitter.emit('validated', { scope: 'field', field, ...res, warnings });

      // 完成并清理
      const pending = this.fieldPending.get(field);
      pending?.resolve(res);
      this.fieldPending.delete(field);
      this.fieldTimers.delete(field);
      this.fieldLatestArgs.delete(field);
    }, this.debounceMs);

    this.fieldTimers.set(field, timer);
    return this.fieldPending.get(field)!.promise;
  }

  /**
   * 校验整个表单,聚合所有字段错误。
   * 默认沿用字段级防抖行为(含异步规则的字段会等待防抖后执行)。
   * @param values 表单值
   * @param context 额外上下文(默认会与 values 合并,便于跨字段规则访问)
   * @returns Promise<{ valid: boolean; errors: Record<string, string[]> }>
   */
  public async validateForm(
    values: Values,
    context?: Ctx
  ): Promise<{ valid: boolean; errors: Record<string, string[]> }> {
    this.ensureNotDisposed();
    const ctx: Ctx = { ...(values ?? {}), ...(context ?? {}) };

    const fields = [...this.rules.keys()];
    const results = await Promise.all(
      fields.map((f) => this.validateField(f, values[f], ctx))
    );

    // 聚合错误(此处使用内部 errors Map 更稳妥)
    const errorRecord: Record<string, string[]> = {};
    for (const [field, msgs] of this.errors) {
      errorRecord[field] = msgs.slice();
    }
    const valid = results.every((r) => r.valid);

    this.emitter.emit('validated', {
      scope: 'form',
      valid,
      errors: errorRecord,
    });

    return { valid, errors: errorRecord };
  }

  /**
   * 切换语言,可增量注入消息模板(与现有模板合并)。
   * @param locale 目标语言
   * @param messages 可选,增量消息模板
   */
  public setLocale(locale: Locale, messages?: Record<string, string>): void {
    this.ensureNotDisposed();
    if (messages) {
      this.messages[locale] = { ...(this.messages[locale] ?? {}), ...messages };
    }
    this.locale = locale;
  }

  /**
   * 获取单字段或全部错误。
   * @param field 可选,字段名
   */
  public getErrors(field?: string): string[] | Record<string, string[]> {
    this.ensureNotDisposed();
    if (field) {
      return this.errors.get(field) ?? [];
    }
    const all: Record<string, string[]> = {};
    for (const [k, v] of this.errors) all[k] = v.slice();
    return all;
  }

  /**
   * 清空单字段或全部错误并发出 'validated' 事件。
   * @param field 可选,字段名
   */
  public clearErrors(field?: string): void {
    this.ensureNotDisposed();
    if (field) {
      this.errors.delete(field);
      this.emitter.emit('validated', {
        scope: 'field',
        field,
        valid: true,
        errors: [],
        warnings: [],
      });
      return;
    }
    this.errors.clear();
    this.emitter.emit('validated', { scope: 'form', valid: true, errors: {} });
  }

  /**
   * 设置异步校验防抖时间(毫秒)。
   * @param ms 毫秒数
   */
  public useDebounce(ms: number): void {
    this.ensureNotDisposed();
    this.debounceMs = Math.max(0, ms);
  }

  /**
   * 解绑事件、清理资源并标记 disposed。
   */
  public dispose(): void {
    if (this.disposed) return;
    this.disposed = true;
    // 清理防抖定时器
    for (const t of this.fieldTimers.values()) clearTimeout(t);
    this.fieldTimers.clear();
    // 使未决 promise 安全完成
    for (const [field, pending] of this.fieldPending) {
      try {
        pending.resolve({ valid: false, errors: ['Disposed'] });
      } catch {
        /* ignore */
      }
      this.emitter.emit('error', { scope: 'field', field, error: new Error('Disposed') });
    }
    this.fieldPending.clear();
    this.fieldLatestArgs.clear();
    // 不移除外部 emitter 的监听者,仅派发一次 disposed 事件
    this.emitter.emit('disposed', { disposed: true });
  }

  // 可选:允许在运行时替换消息格式化器(可插拔)
  public setMessageFormatter(formatter: MessageFormatter): void {
    this.ensureNotDisposed();
    this.formatter = formatter;
  }

  // ------ helpers ------

  private setFieldErrors(field: string, messages: string[]) {
    if (messages.length > 0) this.errors.set(field, messages);
    else this.errors.delete(field);
  }

  private ensureNotDisposed() {
    if (this.disposed) {
      throw new Error('FormValidator has been disposed.');
    }
  }
}

方法签名与返回类型说明:

  • addRule(field: string, rule: ValidationRule | ValidationRule[], options?: { prepend?: boolean }): void

    • 参数:字段名;规则或规则数组;可选是否前置插入
    • 返回:void
  • removeRule(field: string, ruleName?: string): number

    • 参数:字段名;可选的规则名称
    • 返回:移除的规则数量
  • validateField(field: string, value: unknown, context?: Record<string, unknown>): Promise

    • 参数:字段名;值;可选上下文(建议传整个表单值以支持跨字段校验)
    • 返回:Promise,包含 valid 与 errors
  • validateForm(values: Record<string, unknown>, context?: Record<string, unknown>): Promise<{ valid: boolean; errors: Record<string, string[]> }>

    • 参数:表单值;可选上下文(默认与 values 合并)
    • 返回:Promise,包含整体 valid 与按字段聚合的 errors
  • setLocale(locale: 'en' | 'zh' | 'es', messages?: Record<string, string>): void

    • 参数:目标语言;可选增量消息模板(会与已有模板合并)
    • 返回:void
  • getErrors(field?: string): string[] | Record<string, string[]>

    • 参数:可选字段名
    • 返回:若传字段名返回该字段错误数组,否则返回所有字段错误映射
  • clearErrors(field?: string): void

    • 参数:可选字段名
    • 返回:void,同时派发 validated 事件
  • useDebounce(ms: number): void

    • 参数:防抖间隔毫秒
    • 返回:void
  • dispose(): void

    • 参数:无
    • 返回:void,清理资源并标记 disposed

设计要点与说明:

  • 动态增删规则:rules 为 Map,addRule/removeRule 即时生效。
  • 同步/异步混合:统一在 validateField 中顺序 await;存在异步规则时采用字段级防抖合并,减少频繁远程请求(如用户名唯一性)。
  • 跨字段依赖:将整个 values 合并进 context,规则实现中可通过 ctx.otherField 读取其它字段。
  • 本地化与消息格式化:消息模板源自 messages[locale][rule.name];支持 rule.message 覆盖。formatter 可插拔,默认提供 {key} 插值。
  • 事件通知:emitter.emit('validated' | 'error' | 'disposed', payload) 解耦 UI;组件可订阅相应事件联动渲染。
  • 错误存储:errors 为 Map<string, string[]>,仅记录 severity !== 'warning' 的错误。warning 将通过事件 payload 返回,便于 UI 单独显示。
  • 防抖策略:含异步规则的字段采用 last-call-wins 合并,短时间多次 validateField 调用将复用同一 Promise,最终以最后一次的值为准。
  • 资源释放:dispose 会清理定时器、结束未决 Promise 并置位 disposed,防止内存泄漏与误用。

// Domain model for an e-commerce Order aggregate (DDD-oriented)

import java.math.BigDecimal; import java.math.RoundingMode; import java.time.Instant; import java.util.*; import java.util.stream.Collectors;

public final class OrderAggregate {

// --------- Key fields (Aggregate state) ---------
private final String orderId;                      // 订单唯一标识
private final String customerId;                   // 用户标识
private final List<OrderItem> items;               // 行项
private Money subtotal;                            // 小计
private Money discount;                            // 折扣金额
private Money total;                               // 应付总额
private OrderStatus status;                        // 状态
private Instant createdAt;                         // 创建时间
private Instant updatedAt;                         // 最近修改
private final List<DomainEvent> domainEvents;      // 未提交事件
private final Map<String, Object> metadata;        // 拓展信息(渠道等)

// ---------- Factory ----------
public static OrderAggregate create(String orderId, String customerId, String currency, Map<String, Object> metadata) {
    Objects.requireNonNull(orderId, "orderId");
    Objects.requireNonNull(customerId, "customerId");
    Objects.requireNonNull(currency, "currency");
    Instant now = Instant.now();
    return new OrderAggregate(
            orderId,
            customerId,
            new ArrayList<>(),
            Money.zero(currency),
            Money.zero(currency),
            Money.zero(currency),
            OrderStatus.CREATED,
            now,
            now,
            new ArrayList<>(),
            metadata == null ? new HashMap<>() : new HashMap<>(metadata)
    );
}

private OrderAggregate(
        String orderId,
        String customerId,
        List<OrderItem> items,
        Money subtotal,
        Money discount,
        Money total,
        OrderStatus status,
        Instant createdAt,
        Instant updatedAt,
        List<DomainEvent> domainEvents,
        Map<String, Object> metadata
) {
    this.orderId = orderId;
    this.customerId = customerId;
    this.items = items;
    this.subtotal = subtotal;
    this.discount = discount;
    this.total = total;
    this.status = status;
    this.createdAt = createdAt;
    this.updatedAt = updatedAt;
    this.domainEvents = domainEvents;
    this.metadata = metadata;
}

// ---------- Commands (intention-revealing) ----------

// 新增行项(仅允许在 CREATED 状态)
public OrderAggregate addItem(String productId, String name, Money price, int quantity) {
    assertState(OrderStatus.CREATED, "addItem only allowed in CREATED");
    Objects.requireNonNull(productId, "productId");
    Objects.requireNonNull(name, "name");
    Objects.requireNonNull(price, "price");
    if (quantity <= 0) throw new IllegalArgumentException("quantity must be > 0");
    ensureMoneyCurrency(price);

    Optional<OrderItem> existing = items.stream()
            .filter(it -> it.getProductId().equals(productId))
            .findFirst();

    if (existing.isPresent()) {
        OrderItem e = existing.get();
        int newQty = e.getQuantity() + quantity;
        OrderItem updated = new OrderItem(e.getProductId(), e.getName(), e.getPrice(), newQty);
        int idx = items.indexOf(e);
        items.set(idx, updated);
    } else {
        items.add(new OrderItem(productId, name, price, quantity));
    }
    calculateTotals();
    touch();
    return this;
}

// 移除行项(仅允许在 CREATED 状态)
public OrderAggregate removeItem(String productId) {
    assertState(OrderStatus.CREATED, "removeItem only allowed in CREATED");
    Objects.requireNonNull(productId, "productId");
    boolean removed = items.removeIf(it -> it.getProductId().equals(productId));
    if (!removed) return this; // idempotent
    calculateTotals();
    touch();
    return this;
}

// 应用折扣策略(仅允许在 CREATED 状态)
// 返回折扣金额(以 subtotal 的货币计)
public BigDecimal applyDiscountCode(String code, DiscountPolicy policy) {
    assertState(OrderStatus.CREATED, "applyDiscountCode only allowed in CREATED");
    Objects.requireNonNull(policy, "policy");

    // 透传上下文,可包含渠道、用户等级等
    Map<String, Object> ctx = new HashMap<>(metadata);
    ctx.put("orderId", orderId);
    ctx.put("customerId", customerId);
    ctx.put("itemsCount", items.size());
    ctx.put("subtotal", subtotal.getAmount());

    BigDecimal computed = policy.compute(this.subtotal, code, ctx);
    if (computed == null) computed = BigDecimal.ZERO;
    if (computed.signum() < 0) computed = BigDecimal.ZERO;

    Money candidate = Money.of(computed, subtotal.getCurrency());
    // 折扣不得超过小计
    if (candidate.compareTo(subtotal) > 0) {
        candidate = subtotal;
    }
    this.discount = candidate;
    calculateTotals();
    touch();
    return this.discount.getAmount();
}

// 重算金额(内部一致性)
public void calculateTotals() {
    // 小计
    Money newSubtotal = Money.zero(subtotal.getCurrency());
    for (OrderItem it : items) {
        ensureMoneyCurrency(it.getPrice());
        Money line = it.getPrice().multiply(it.getQuantity());
        newSubtotal = newSubtotal.add(line);
    }
    this.subtotal = newSubtotal;

    // 折扣边界
    if (discount == null) {
        this.discount = Money.zero(subtotal.getCurrency());
    } else {
        ensureMoneyCurrency(discount);
        if (discount.signum() < 0) discount = Money.zero(subtotal.getCurrency());
        if (discount.compareTo(subtotal) > 0) discount = subtotal;
    }

    // 目前 total = subtotal - discount(运费/税费可通过扩展点加入)
    Money result = subtotal.subtract(discount);
    if (result.signum() < 0) result = Money.zero(subtotal.getCurrency());
    this.total = result;

    touch();
}

// 支付(外部已确认库存与支付成功后调用)
public void pay(String paymentId, Instant paidAt) {
    Objects.requireNonNull(paymentId, "paymentId");
    if (paidAt == null) paidAt = Instant.now();

    if (status != OrderStatus.CREATED) {
        throw new IllegalStateException("Only CREATED can be paid");
    }
    if (items.isEmpty()) {
        throw new IllegalStateException("Cannot pay an order without items");
    }

    this.status = OrderStatus.PAID;
    touch();

    domainEvents.add(new PaymentSucceeded(
            orderId, customerId, paymentId, total, paidAt
    ));
}

// 发货(仅 PAID -> SHIPPED)
public void ship(String trackingNo, String carrier, Instant shippedAt) {
    Objects.requireNonNull(trackingNo, "trackingNo");
    Objects.requireNonNull(carrier, "carrier");
    if (shippedAt == null) shippedAt = Instant.now();

    if (status != OrderStatus.PAID) {
        throw new IllegalStateException("Only PAID can be shipped");
    }

    this.status = OrderStatus.SHIPPED;
    touch();

    domainEvents.add(new OrderShipped(orderId, trackingNo, carrier, shippedAt));
}

// 取消订单(CREATED/PAID -> CANCELED,记录原因)
public void cancel(String reason) {
    Objects.requireNonNull(reason, "reason");
    if (status == OrderStatus.SHIPPED) {
        throw new IllegalStateException("Shipped order cannot be canceled");
    }
    if (status == OrderStatus.CANCELED) {
        return; // idempotent
    }
    this.status = OrderStatus.CANCELED;
    touch();

    domainEvents.add(new OrderCanceled(orderId, customerId, reason, Instant.now()));
}

// 导出只读 DTO(供查询或 API 返回)
public OrderDTO toDTO() {
    OrderDTO dto = new OrderDTO();
    dto.orderId = this.orderId;
    dto.customerId = this.customerId;
    dto.items = Collections.unmodifiableList(new ArrayList<>(this.items));
    dto.total = this.total;
    dto.status = this.status;
    return dto;
}

// 获取未提交事件(仓储提交成功后应清空)
public List<DomainEvent> getUncommittedEvents() {
    return Collections.unmodifiableList(new ArrayList<>(domainEvents));
}

// 可选:由仓储在成功持久化与发布后调用
public void clearUncommittedEvents() {
    domainEvents.clear();
}

// ---------- Invariants & helpers ----------
private void assertState(OrderStatus expected, String message) {
    if (this.status != expected) throw new IllegalStateException(message);
}

private void ensureMoneyCurrency(Money m) {
    if (!Objects.equals(m.getCurrency(), this.subtotal.getCurrency())) {
        throw new IllegalArgumentException("Money currency mismatch: expected " + this.subtotal.getCurrency()
                + " but was " + m.getCurrency());
    }
}

private void touch() {
    this.updatedAt = Instant.now();
}

// ---------- Accessors ----------
public String getOrderId() { return orderId; }
public String getCustomerId() { return customerId; }
public List<OrderItem> getItems() { return Collections.unmodifiableList(items); }
public Money getSubtotal() { return subtotal; }
public Money getDiscount() { return discount; }
public Money getTotal() { return total; }
public OrderStatus getStatus() { return status; }
public Instant getCreatedAt() { return createdAt; }
public Instant getUpdatedAt() { return updatedAt; }
public Map<String, Object> getMetadata() { return Collections.unmodifiableMap(metadata); }

// ---------- Supporting types ----------

public static final class OrderItem {
    private final String productId;
    private final String name;
    private final Money price;
    private final int quantity;

    public OrderItem(String productId, String name, Money price, int quantity) {
        this.productId = Objects.requireNonNull(productId, "productId");
        this.name = Objects.requireNonNull(name, "name");
        this.price = Objects.requireNonNull(price, "price");
        if (quantity <= 0) throw new IllegalArgumentException("quantity must be > 0");
        this.quantity = quantity;
    }

    public String getProductId() { return productId; }
    public String getName() { return name; }
    public Money getPrice() { return price; }
    public int getQuantity() { return quantity; }

    public Money lineTotal() { return price.multiply(quantity); }
}

public static final class Money implements Comparable<Money> {
    private final BigDecimal amount;
    private final String currency;

    public static Money of(BigDecimal amount, String currency) {
        Objects.requireNonNull(amount, "amount");
        Objects.requireNonNull(currency, "currency");
        return new Money(amount.setScale(2, RoundingMode.HALF_UP), currency);
    }

    public static Money of(long minorUnits, String currency) {
        BigDecimal amt = BigDecimal.valueOf(minorUnits).movePointLeft(2);
        return of(amt, currency);
    }

    public static Money zero(String currency) {
        return new Money(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP), currency);
    }

    private Money(BigDecimal amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public Money add(Money other) {
        checkCurrency(other);
        return of(this.amount.add(other.amount), currency);
    }

    public Money subtract(Money other) {
        checkCurrency(other);
        return of(this.amount.subtract(other.amount), currency);
    }

    public Money multiply(int times) {
        if (times < 0) throw new IllegalArgumentException("times must be >= 0");
        return of(this.amount.multiply(BigDecimal.valueOf(times)), currency);
    }

    public int compareTo(Money o) {
        checkCurrency(o);
        return this.amount.compareTo(o.amount);
    }

    public int signum() {
        return amount.signum();
    }

    public BigDecimal getAmount() { return amount; }
    public String getCurrency() { return currency; }

    private void checkCurrency(Money other) {
        if (!Objects.equals(this.currency, other.currency)) {
            throw new IllegalArgumentException("Currency mismatch: " + this.currency + " vs " + other.currency);
        }
    }

    @Override public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Money)) return false;
        Money money = (Money) o;
        return amount.compareTo(money.amount) == 0 && Objects.equals(currency, money.currency);
    }

    @Override public int hashCode() {
        return Objects.hash(amount.stripTrailingZeros(), currency);
    }

    @Override public String toString() {
        return amount.toPlainString() + " " + currency;
    }
}

public enum OrderStatus {
    CREATED, PAID, SHIPPED, CANCELED
}

public interface DomainEvent {
    String type();
    Instant occurredAt();
}

// --------- Domain events ---------
public static final class PaymentSucceeded implements DomainEvent {
    private final String orderId;
    private final String customerId;
    private final String paymentId;
    private final Money paidAmount;
    private final Instant occurredAt;

    public PaymentSucceeded(String orderId, String customerId, String paymentId, Money paidAmount, Instant occurredAt) {
        this.orderId = orderId;
        this.customerId = customerId;
        this.paymentId = paymentId;
        this.paidAmount = paidAmount;
        this.occurredAt = occurredAt;
    }

    @Override public String type() { return "PaymentSucceeded"; }
    @Override public Instant occurredAt() { return occurredAt; }

    public String getOrderId() { return orderId; }
    public String getCustomerId() { return customerId; }
    public String getPaymentId() { return paymentId; }
    public Money getPaidAmount() { return paidAmount; }
}

public static final class OrderShipped implements DomainEvent {
    private final String orderId;
    private final String trackingNo;
    private final String carrier;
    private final Instant occurredAt;

    public OrderShipped(String orderId, String trackingNo, String carrier, Instant occurredAt) {
        this.orderId = orderId;
        this.trackingNo = trackingNo;
        this.carrier = carrier;
        this.occurredAt = occurredAt;
    }

    @Override public String type() { return "OrderShipped"; }
    @Override public Instant occurredAt() { return occurredAt; }

    public String getOrderId() { return orderId; }
    public String getTrackingNo() { return trackingNo; }
    public String getCarrier() { return carrier; }
}

public static final class OrderCanceled implements DomainEvent {
    private final String orderId;
    private final String customerId;
    private final String reason;
    private final Instant occurredAt;

    public OrderCanceled(String orderId, String customerId, String reason, Instant occurredAt) {
        this.orderId = orderId;
        this.customerId = customerId;
        this.reason = reason;
        this.occurredAt = occurredAt;
    }

    @Override public String type() { return "OrderCanceled"; }
    @Override public Instant occurredAt() { return occurredAt; }

    public String getOrderId() { return orderId; }
    public String getCustomerId() { return customerId; }
    public String getReason() { return reason; }
}

// --------- Discount policy port ---------
public interface DiscountPolicy {
    // 返回折扣金额(与 subtotal 的 currency 一致)
    BigDecimal compute(Money subtotal, String code, Map<String, Object> ctx);
}

// --------- Read-only DTO ---------
public static final class OrderDTO {
    public String orderId;
    public String customerId;
    public List<OrderItem> items;
    public Money total;
    public OrderStatus status;
}

}

from __future__ import annotations

import datetime
import hashlib
import json
import logging
import re
import threading
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Tuple, Union


@dataclass(frozen=True)
class Rule:
    """
    单条评估规则。
    - name: 规则名称,便于调试与导出
    - predicate: 上下文判断函数,入参为 context: Dict[str, Any],返回 True/False
    - rollout: 可选的按比例灰度(0-100),当 predicate 为 True 且 identity 命中 rollout 桶时才算匹配
    """
    name: str
    predicate: Callable[[Dict[str, Any]], bool]
    rollout: Optional[int] = None

    def matches(self, context: Optional[Dict[str, Any]], key: str) -> bool:
        """
        计算规则对给定上下文是否命中。
        - 若设置 rollout,需要上下文中可解析的 identity;若缺失 identity,则不命中。
        """
        ctx = context or {}
        try:
            if not self.predicate(ctx):
                return False
        except Exception:
            # 避免业务 predicate 抛错影响整体评估
            return False

        if self.rollout is None:
            return True

        identity = FeatureToggleManager._extract_identity(ctx)
        if identity is None:
            return False  # 没有 identity 时,带 rollout 的规则不命中,避免意外放量

        bucket = FeatureToggleManager.compute_rollout_bucket(key, identity)
        return bucket < int(self.rollout)


@dataclass
class Toggle:
    """
    单个功能开关的定义。
    - key: 唯一键
    - enabled: 顶层开关(全局门禁)。False 时无论规则如何均返回 False;True 时结合规则评估。
    - rules: 可选规则列表;存在时需至少一条规则命中才返回 True。
    """
    key: str
    enabled: bool
    rules: Optional[List[Rule]] = None


class FeatureToggleManager:
    """
    统一管理功能开关的定义、加载、刷新与评估,支持:
    - 本地配置与远程拉取(fetcher)
    - 用户分群与灰度(Rule.predicate + Rule.rollout)
    - 可插拔钩子通知(开关 enabled 基态变化)
    - 线程安全缓存(TTL + RLock)
    适用场景:按环境发布、A/B 实验预埋、回滚策略等。
    """

    # -------------------------
    # 公共属性(按要求暴露)
    # -------------------------
    toggles: Dict[str, Toggle]
    default_state: bool
    fetcher: Optional[Callable[[], Dict[str, Any]]]
    cache_ttl_seconds: int
    last_refresh_at: Optional[datetime.datetime]
    hooks: List[Callable[[str, bool], None]]
    lock: threading.RLock
    logger: logging.Logger

    # -------------------------
    # 初始化
    # -------------------------
    def __init__(
        self,
        default_state: bool = False,
        fetcher: Optional[Callable[[], Dict[str, Any]]] = None,
        cache_ttl_seconds: int = 30,
        logger: Optional[logging.Logger] = None,
        initial_toggles: Optional[Dict[str, Toggle]] = None,
    ) -> None:
        """
        参数:
        - default_state: bool,未命中时的默认值
        - fetcher: 可选远程拉取函数,返回 Dict[str, Any] 的最新开关定义
        - cache_ttl_seconds: 本地缓存 TTL,过期后触发刷新
        - logger: 日志记录器,默认使用模块 logger
        - initial_toggles: 可选初始开关集合
        """
        self.default_state = bool(default_state)
        self.fetcher = fetcher
        self.cache_ttl_seconds = int(cache_ttl_seconds)
        self.logger = logger or logging.getLogger(__name__)
        self.toggles = initial_toggles.copy() if initial_toggles else {}
        self.last_refresh_at = None
        self.hooks = []
        self.lock = threading.RLock()

    # -------------------------
    # 核心 API
    # -------------------------
    def is_enabled(
        self,
        key: str,
        context: Optional[Dict[str, Any]] = None,
        default: Optional[bool] = None,
    ) -> bool:
        """
        基于规则与上下文计算开关是否开启(线程安全)。
        评估规则:
        - 若 key 不存在 => 返回 fallback: default 或 default_state
        - 若 toggle.enabled 为 False => 返回 False
        - 若 toggle.enabled 为 True:
            - 无规则 => True
            - 存在规则 => 任一规则命中且(若配置 rollout)命中桶 => True;否则 False

        参数:
        - key: str,开关键
        - context: 可选 Dict,上下文(如 user_id、country、app_version 等)
        - default: 可选 bool,当 key 不存在时的回退值(优先于 default_state)

        返回:
        - bool,是否开启
        """
        # 自动确保在 TTL 过期时刷新缓存
        self._ensure_fresh()

        with self.lock:
            toggle = self.toggles.get(key)
            if toggle is None:
                return bool(default if default is not None else self.default_state)

            if not toggle.enabled:
                return False

            if not toggle.rules:
                return True

            for rule in toggle.rules:
                try:
                    if rule.matches(context, key):
                        return True
                except Exception as e:
                    self.logger.exception("Rule evaluation failed for %s/%s: %s", key, rule.name, e)
            return False

    def set_toggle(
        self,
        key: str,
        state: bool,
        rules: Optional[List[Rule]] = None,
    ) -> None:
        """
        设置或更新单个开关,触发变更钩子(仅当 enabled 基态变化时)。
        参数:
        - key: str
        - state: bool,enabled 基态
        - rules: 可选规则列表
        返回:
        - None
        """
        with self.lock:
            old = self.toggles.get(key)
            old_enabled = old.enabled if old else None

            self.toggles[key] = Toggle(key=key, enabled=bool(state), rules=rules[:] if rules else None)

            hooks_to_call = []
            if old_enabled is None or bool(state) != bool(old_enabled):
                hooks_to_call = self.hooks[:]

        # 钩子在锁外调用,避免阻塞/死锁
        for cb in hooks_to_call:
            try:
                cb(key, bool(state))
            except Exception as e:
                self.logger.exception("Hook callback failed for %s: %s", key, e)

    def refresh(self, force: bool = False) -> bool:
        """
        在 TTL 过期或强制模式下调用 fetcher 拉取最新开关,成功返回 True。
        参数:
        - force: bool,是否强制刷新(忽略 TTL)
        返回:
        - bool,是否发生了刷新且拉取成功
        """
        if self.fetcher is None:
            return False

        now = datetime.datetime.utcnow()
        with self.lock:
            if not force and self.last_refresh_at is not None:
                age = (now - self.last_refresh_at).total_seconds()
                if age < self.cache_ttl_seconds:
                    return False  # 未过期,无需刷新

        # 调用远程拉取在锁外执行,避免长时间占用锁
        try:
            raw = self.fetcher() or {}
        except Exception as e:
            self.logger.exception("Fetcher failed: %s", e)
            return False

        # 解析并计算变化
        new_toggles, changed_keys = self._parse_remote_payload(raw)

        with self.lock:
            # 对比 enabled 基态的变化(用于钩子)
            enabled_changes = self._diff_enabled_changes(self.toggles, new_toggles)
            self.toggles = new_toggles
            self.last_refresh_at = now
            hooks_to_call = self.hooks[:]
            changed_keys = enabled_changes  # 仅对 enabled 基态变化触发钩子

        for key, enabled in changed_keys:
            for cb in hooks_to_call:
                try:
                    cb(key, enabled)
                except Exception as e:
                    self.logger.exception("Hook callback failed for %s: %s", key, e)

        return True

    def load_from_file(self, path: str) -> int:
        """
        从本地 JSON/YAML 文件加载开关定义,返回加载数量。
        文件格式支持两种顶层结构:
        1) 直接 key -> toggleDef
        2) {"toggles": { key -> toggleDef }}

        toggleDef 支持:
        - 布尔值:true/false
        - 对象:
          {
            "enabled": true/false,
            "rules": [
               {
                 "name": "rule-name",
                 "predicate": "always" | { ... 见 _compile_predicate 文档 ... },
                 "rollout": 30
               }
            ]
          }

        参数:
        - path: str,文件路径(.json/.yaml/.yml)
        返回:
        - int,成功加载的开关数量
        """
        content: Dict[str, Any]
        if path.lower().endswith(".json"):
            with open(path, "r", encoding="utf-8") as f:
                content = json.load(f)
        elif path.lower().endswith((".yml", ".yaml")):
            try:
                import yaml  # type: ignore
            except Exception as e:
                raise RuntimeError("PyYAML is required to load YAML files") from e
            with open(path, "r", encoding="utf-8") as f:
                content = yaml.safe_load(f) or {}
        else:
            raise ValueError("Unsupported file extension. Use .json, .yaml or .yml")

        toggles_obj = content.get("toggles", content)
        if not isinstance(toggles_obj, dict):
            raise ValueError("Invalid toggle file format")

        new_toggles: Dict[str, Toggle] = {}
        for key, val in toggles_obj.items():
            t = self._parse_toggle_entry(str(key), val)
            new_toggles[key] = t

        with self.lock:
            enabled_changes = self._diff_enabled_changes(self.toggles, new_toggles)
            self.toggles.update(new_toggles)
            hooks_to_call = self.hooks[:]

        for key, enabled in enabled_changes:
            for cb in hooks_to_call:
                try:
                    cb(key, enabled)
                except Exception as e:
                    self.logger.exception("Hook callback failed for %s: %s", key, e)

        return len(new_toggles)

    def register_hook(self, cb: Callable[[str, bool], None]) -> None:
        """
        注册开关 enabled 基态变化的通知回调。
        参数:
        - cb: Callable[[str, bool], None],签名为 (key, enabled)
        返回:
        - None
        """
        if not callable(cb):
            raise ValueError("hook must be callable")
        with self.lock:
            self.hooks.append(cb)

    def export_state(self) -> Dict[str, Any]:
        """
        导出当前开关快照,便于调试或持久化(不导出 predicate 可执行体,仅导出规则元信息)。
        返回:
        - Dict[str, Any],包含 toggles、default_state、cache_ttl_seconds、last_refresh_at
        """
        with self.lock:
            snapshot: Dict[str, Any] = {
                "default_state": self.default_state,
                "cache_ttl_seconds": self.cache_ttl_seconds,
                "last_refresh_at": self.last_refresh_at.isoformat() if self.last_refresh_at else None,
                "toggles": {},
            }
            for k, t in self.toggles.items():
                snapshot["toggles"][k] = {
                    "enabled": t.enabled,
                    "rules": [{"name": r.name, "rollout": r.rollout} for r in (t.rules or [])],
                }
        return snapshot

    # -------------------------
    # 线程安全缓存辅助
    # -------------------------
    def _ensure_fresh(self) -> None:
        """
        若 TTL 过期尝试刷新(非强制),fetcher 可能为 None。
        """
        if self.fetcher is None or self.cache_ttl_seconds <= 0:
            return

        need_refresh = False
        now = datetime.datetime.utcnow()

        with self.lock:
            if self.last_refresh_at is None:
                need_refresh = True
            else:
                age = (now - self.last_refresh_at).total_seconds()
                if age >= self.cache_ttl_seconds:
                    need_refresh = True

        if need_refresh:
            try:
                self.refresh(force=False)
            except Exception as e:
                self.logger.exception("Auto refresh failed: %s", e)

    # -------------------------
    # 解析与编译
    # -------------------------
    def _parse_remote_payload(self, raw: Dict[str, Any]) -> Tuple[Dict[str, Toggle], List[Tuple[str, bool]]]:
        """
        将 fetcher 返回的原始字典解析为 Toggle 集合。
        返回: (new_toggles, changed_enabled_pairs),其中 changed_enabled_pairs 在此阶段不计算,
        实际“变化”由 _diff_enabled_changes 决定;此处返回空列表即可。
        """
        toggles_obj = raw.get("toggles", raw)
        new_toggles: Dict[str, Toggle] = {}
        if not isinstance(toggles_obj, dict):
            self.logger.warning("Fetcher payload is not a dict")
            return {}, []

        for key, val in toggles_obj.items():
            try:
                t = self._parse_toggle_entry(str(key), val)
                new_toggles[key] = t
            except Exception as e:
                self.logger.exception("Failed to parse toggle %s: %s", key, e)

        return new_toggles, []

    def _parse_toggle_entry(self, key: str, val: Any) -> Toggle:
        """
        解析单个 toggle 条目。
        支持:
        - bool => enabled=val, rules=None
        - dict => 需要 enabled 字段,可含 rules
        """
        if isinstance(val, bool):
            return Toggle(key=key, enabled=val, rules=None)

        if isinstance(val, dict):
            if "enabled" not in val:
                raise ValueError(f"Toggle {key} missing 'enabled'")
            enabled = bool(val.get("enabled"))
            raw_rules = val.get("rules") or []
            rules: List[Rule] = []
            for r in raw_rules:
                if not isinstance(r, dict):
                    raise ValueError(f"Toggle {key} rules item must be object")
                name = str(r.get("name") or "rule")
                rollout = r.get("rollout")
                if rollout is not None:
                    rollout = int(rollout)
                    if rollout < 0 or rollout > 100:
                        raise ValueError(f"Toggle {key} rule {name} rollout must be 0..100")

                pred_spec = r.get("predicate", "always")
                predicate = self._compile_predicate(pred_spec)
                rules.append(Rule(name=name, predicate=predicate, rollout=rollout))

            return Toggle(key=key, enabled=enabled, rules=rules or None)

        raise ValueError(f"Unsupported toggle definition for {key}")

    # 简易谓词编译器:支持常见条件组合,满足多数灰度/分群场景
    def _compile_predicate(self, spec: Any) -> Callable[[Dict[str, Any]], bool]:
        """
        支持的 spec 形式:
        - "always" => 恒真
        - {"eq": {"field": "country", "value": "US"}}
        - {"in": {"field": "country", "values": ["US", "CA"]}}
        - {"regex": {"field": "app_version", "pattern": "^2\\."}}
        - {"gte": {"field": "build", "value": 120}}  数字比较
        - {"any": [spec1, spec2, ...]}
        - {"all": [spec1, spec2, ...]}
        - {"not": spec}
        """
        if spec == "always" or spec is True or spec is None:
            return lambda ctx: True

        if not isinstance(spec, dict) or len(spec) != 1:
            raise ValueError(f"Unsupported predicate spec: {spec}")

        op, arg = next(iter(spec.items()))

        if op == "eq":
            field, value = arg["field"], arg["value"]
            return lambda ctx: ctx.get(field) == value

        if op == "in":
            field, values = arg["field"], set(arg["values"])
            return lambda ctx: ctx.get(field) in values

        if op == "regex":
            field, pattern = arg["field"], arg["pattern"]
            regex = re.compile(pattern)
            return lambda ctx: isinstance(ctx.get(field), str) and bool(regex.search(ctx[field]))

        if op == "gte":
            field, value = arg["field"], arg["value"]
            return lambda ctx: FeatureToggleManager._to_number(ctx.get(field)) >= FeatureToggleManager._to_number(value)

        if op == "any":
            subs = [self._compile_predicate(s) for s in (arg or [])]
            return lambda ctx: any(p(ctx) for p in subs)

        if op == "all":
            subs = [self._compile_predicate(s) for s in (arg or [])]
            return lambda ctx: all(p(ctx) for p in subs)

        if op == "not":
            sub = self._compile_predicate(arg)
            return lambda ctx: not sub(ctx)

        raise ValueError(f"Unknown predicate operator: {op}")

    # -------------------------
    # 工具方法
    # -------------------------
    @staticmethod
    def _to_number(v: Any) -> float:
        try:
            return float(v)
        except Exception:
            return float("nan")

    @staticmethod
    def _extract_identity(context: Dict[str, Any]) -> Optional[str]:
        """
        从上下文中提取稳定 identity,用于一致性灰度。
        常用字段:user_id/uid/id/device_id/session_id/account/email
        """
        candidates = ("user_id", "uid", "id", "device_id", "session_id", "account", "email")
        for k in candidates:
            if k in context and context[k] is not None:
                return str(context[k])
        return None

    @staticmethod
    def compute_rollout_bucket(key: str, identity: str, buckets: int = 100) -> int:
        """
        基于 key + identity 生成 0..(buckets-1) 的稳定桶值(默认 0..99)。
        """
        seed = f"{key}:{identity}".encode("utf-8")
        digest = hashlib.sha256(seed).hexdigest()
        as_int = int(digest[:8], 16)  # 取前 32bit 足够
        return as_int % buckets

    @staticmethod
    def _diff_enabled_changes(
        old: Dict[str, Toggle],
        new: Dict[str, Toggle],
    ) -> List[Tuple[str, bool]]:
        """
        计算 enabled 基态的变化,用于触发钩子。
        返回: [(key, new_enabled), ...]
        """
        changes: List[Tuple[str, bool]] = []
        old_keys = set(old.keys())
        new_keys = set(new.keys())
        for k in new_keys.union(old_keys):
            old_enabled = old.get(k).enabled if k in old else None
            new_enabled = new.get(k).enabled if k in new else None
            if old_enabled is None and new_enabled is not None:
                changes.append((k, bool(new_enabled)))
            elif new_enabled is None:
                # 新集合中不存在,认为删除,不触发(也可选择触发 False)
                continue
            elif bool(old_enabled) != bool(new_enabled):
                changes.append((k, bool(new_enabled)))
        return changes

示例详情

📖 如何使用

30秒出活:复制 → 粘贴 → 搞定
与其花几十分钟和AI聊天、试错,不如直接复制这些经过千人验证的模板,修改几个 {{变量}} 就能立刻获得专业级输出。省下来的时间,足够你轻松享受两杯咖啡!
加载中...
💬 不会填参数?让 AI 反过来问你
不确定变量该填什么?一键转为对话模式,AI 会像资深顾问一样逐步引导你,问几个问题就能自动生成完美匹配你需求的定制结果。零门槛,开口就行。
转为对话模式
🚀 告别复制粘贴,Chat 里直接调用
无需切换,输入 / 唤醒 8000+ 专家级提示词。 插件将全站提示词库深度集成于 Chat 输入框。基于当前对话语境,系统智能推荐最契合的 Prompt 并自动完成参数化,让海量资源触手可及,从此彻底告别"手动搬运"。
即将推出
🔌 接口一调,提示词自己会进化
手动跑一次还行,跑一百次呢?通过 API 接口动态注入变量,接入批量评价引擎,让程序自动迭代出更高质量的提示词方案。Prompt 会自己进化,你只管收结果。
发布 API
🤖 一键变成你的专属 Agent 应用
不想每次都配参数?把这条提示词直接发布成独立 Agent,内嵌图片生成、参数优化等工具,分享链接就能用。给团队或客户一个"开箱即用"的完整方案。
创建 Agent

✅ 特性总结

根据用户需求,自动化生成清晰的类与模块结构,提高开发效率。
支持主流编程语言,轻松适配多种开发场景与项目需求。
智能推荐关键属性和方法,确保设计的类结构覆盖主要功能。
详细说明方法参数与返回类型,助力代码逻辑更规范易懂。
灵活定义类责任范围,满足复杂业务场景中的个性化需求。
强调面向对象设计原则,帮助用户构建高复用性和可扩展性系统。
一键生成标准化设计模板,便于团队协作与代码审查。
支持精准描述复杂属性与方法逻辑,助力高级开发者高效设计。
从零开始到完整生成,快速搭建符合需求的类结构。

🎯 解决的问题

帮助用户快速生成清晰、专业的类模块结构,包括属性和方法的详细说明,以满足软件开发中的架构设计需求。

🕒 版本历史

当前版本
v2.1 2024-01-15
优化输出结构,增强情节连贯性
  • ✨ 新增章节节奏控制参数
  • 🔧 优化人物关系描述逻辑
  • 📝 改进主题深化引导语
  • 🎯 增强情节转折点设计
v2.0 2023-12-20
重构提示词架构,提升生成质量
  • 🚀 全新的提示词结构设计
  • 📊 增加输出格式化选项
  • 💡 优化角色塑造引导
v1.5 2023-11-10
修复已知问题,提升稳定性
  • 🐛 修复长文本处理bug
  • ⚡ 提升响应速度
v1.0 2023-10-01
首次发布
  • 🎉 初始版本上线
COMING SOON
版本历史追踪,即将启航
记录每一次提示词的进化与升级,敬请期待。

💬 用户评价

4.8
⭐⭐⭐⭐⭐
基于 28 条评价
5星
85%
4星
12%
3星
3%
👤
电商运营 - 张先生
⭐⭐⭐⭐⭐ 2025-01-15
双十一用这个提示词生成了20多张海报,效果非常好!点击率提升了35%,节省了大量设计时间。参数调整很灵活,能快速适配不同节日。
效果好 节省时间
👤
品牌设计师 - 李女士
⭐⭐⭐⭐⭐ 2025-01-10
作为设计师,这个提示词帮我快速生成创意方向,大大提升了工作效率。生成的海报氛围感很强,稍作调整就能直接使用。
创意好 专业
COMING SOON
用户评价与反馈系统,即将上线
倾听真实反馈,在这里留下您的使用心得,敬请期待。
加载中...