Skip to content

契约定义

概述

契约定义是 Shared 层的核心,定义了功能包之间的通信协议。

什么是契约

契约是功能包对外提供服务的接口定义,它:

  • 定义服务的方法签名
  • 定义数据结构
  • 实现功能包之间的解耦

定义契约

服务契约

typescript
// shared/contracts/IUserService.ets
export interface IUserService {
  /**
   * 获取用户信息
   * @param userId 用户 ID
   * @returns 用户信息
   */
  getUserInfo(userId: string): Promise<UserInfo>;

  /**
   * 更新用户信息
   * @param info 用户信息
   */
  updateUserInfo(info: UserInfo): Promise<void>;

  /**
   * 删除用户
   * @param userId 用户 ID
   */
  deleteUser(userId: string): Promise<void>;
}

数据契约

typescript
// shared/contracts/IAuthService.ets
export interface IAuthService {
  /**
   * 登录
   * @param request 登录请求
   * @returns 登录结果
   */
  login(request: LoginRequest): Promise<LoginResponse>;

  /**
   * 登出
   */
  logout(): Promise<void>;

  /**
   * 检查登录状态
   * @returns 是否已登录
   */
  isLoggedIn(): boolean;
}

实现契约

在功能包中实现契约:

typescript
// packages/user/services/UserService.ets
import { IUserService } from "@shared/contracts";

export class UserServiceImpl implements IUserService {
  async getUserInfo(userId: string): Promise<UserInfo> {
    // 实现逻辑
    const response = await this.httpClient.get(`/users/${userId}`);
    return response.data;
  }

  async updateUserInfo(info: UserInfo): Promise<void> {
    // 实现逻辑
    await this.httpClient.put(`/users/${info.id}`, info);
  }

  async deleteUser(userId: string): Promise<void> {
    // 实现逻辑
    await this.httpClient.delete(`/users/${userId}`);
  }
}

注册契约

在功能包生命周期中注册契约实现:

typescript
/**
 * 用户模块
 * 实现 FeatureModule 接口,支持自动注册
 */
export class UserModule implements FeatureModule {
  /**
   * 模块唯一标识
   */
  readonly moduleId: string = 'user';

  /**
   * 模块名称
   */
  readonly moduleName: string = '用户模块';

  /**
   * 模块版本
   */
  readonly version: string = '1.0.0';

  /**
   * 模块依赖
   */
  readonly dependencies: string[] = ['auth'];

  /**
   * 注册 DI 服务
   * @param container DI 容器
   */
  registerServices(container: Container): void {
    // 注册本模块服务
    container.register<IUserNavSvc>(USER_NAV_SVC_KEY, () => new UserNavSvcImpl());
    container.register<IUserService>("IUserService", () => new UserServiceImpl());
  }

  /**
   * 注册路由
   * @param registry 路由注册器
   */
  registerRoutes(registry: RouteRegistry): void {
    // 注册用户页路由
    registry.register(UserRoutes.Profile, profileNavBuilderWrapper);
  }

  /**
   * 注册路由守卫
   * @param navigationService 导航服务
   */
  registerGuards(navigationService: NavigationService): void {
    // 用户模块不需要额外的守卫,依赖 auth 模块的认证守卫
  }

  /**
   * 模块初始化
   * @param context 模块上下文
   */
  async onInit(context: ModuleContext): Promise<void> {
    console.info(`[UserModule] 模块初始化完成: ${this.moduleName} v${this.version}`);
  }

  /**
   * 模块销毁
   */
  onDestroy(): void {
    console.info(`[UserModule] 模块已销毁: ${this.moduleName}`);
  }
}

使用契约

在其他功能包中使用契约:

typescript
import { getContainer } from "@core/di";
import { IUserService } from "@shared/contracts";

export class MainViewModel {
  private userService: IUserService;

  constructor() {
    const container = getContainer();
    this.userService = container.resolve<IUserService>("IUserService");
  }

  async loadUserInfo(): Promise<void> {
    const userInfo = await this.userService.getUserInfo("123");
    // 使用用户信息
  }
}

契约设计原则

1. 接口隔离原则

每个契约只定义必要的方法:

typescript
// 好的设计
export interface IUserService {
  getUserInfo(userId: string): Promise<UserInfo>;
  updateUserInfo(info: UserInfo): Promise<void>;
}

// 不好的设计
export interface IUserService {
  getUserInfo(userId: string): Promise<UserInfo>;
  updateUserInfo(info: UserInfo): Promise<void>;
  deleteUser(userId: string): Promise<void>;
  resetPassword(userId: string): Promise<void>;
  sendEmail(userId: string, content: string): Promise<void>;
  // 太多方法,应该拆分
}

2. 依赖倒置原则

依赖抽象(契约),而不是具体实现:

typescript
// 推荐
export class MainViewModel {
  private userService: IUserService;  // 依赖契约

  constructor() {
    this.userService = container.resolve<IUserService>("IUserService");
  }
}

// 不推荐
export class MainViewModel {
  private userService: UserService;  // 依赖具体实现

  constructor() {
    this.userService = new UserService();
  }
}

3. 单一职责原则

每个契约只负责一个领域:

typescript
// 推荐
export interface IUserService {
  // 用户相关操作
}

export interface IAuthService {
  // 认证相关操作
}

// 不推荐
export interface IUserAuthService {
  // 混合了用户和认证操作
}

最佳实践

1. 使用 JSDoc 注释

为契约方法添加详细的注释:

typescript
export interface IUserService {
  /**
   * 获取用户信息
   * @param userId 用户 ID
   * @returns 用户信息,如果用户不存在则返回 null
   * @throws {Error} 网络错误或服务器错误
   */
  getUserInfo(userId: string): Promise<UserInfo | null>;
}

2. 使用类型安全

充分利用 TypeScript 的类型系统:

typescript
export interface IUserService {
  getUserInfo(userId: string): Promise<UserInfo>;  // 明确的返回类型
}

// 避免
export interface IUserService {
  getUserInfo(userId: string): Promise<any>;  // 不推荐
}

3. 定义常量键名

定义常量键名,避免字符串拼写错误:

typescript
// shared/contracts/ServiceKeys.ets
export const ServiceKeys = {
  UserService: "IUserService",
  AuthService: "IAuthService",
  ProductService: "IProductService"
};

// 使用
container.register<IUserService>(ServiceKeys.UserService, UserService);
const service = container.resolve<IUserService>(ServiceKeys.UserService);

注意事项

  1. 稳定性:契约一旦定义,应保持稳定
  2. 向后兼容:修改契约时考虑向后兼容
  3. 文档完整:为契约编写完整的文档

下一步