契约定义
概述
契约定义是 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);注意事项
- 稳定性:契约一旦定义,应保持稳定
- 向后兼容:修改契约时考虑向后兼容
- 文档完整:为契约编写完整的文档