渐进式编程课
鸿蒙 目录
第 19 课2026.07.29

适用场景:同一页面需要切换真实服务、测试服务或不同数据源,同时保持页面代码不变

第 19 课:接口抽象与可替换数据服务

  • 日期:2026-07-29
  • 课程序号:第 19 课
  • 知识点:ArkTS 接口、依赖抽象、可替换的数据服务实现
  • 适用场景:同一页面需要切换真实服务、测试服务或不同数据源,同时保持页面代码不变

承接上一课的数据服务拆分:上一课把请求逻辑移出页面;本课再用接口约定服务能力,让页面依赖稳定的方法签名,而不是依赖某个具体实现。

核心概念

接口只描述“能做什么”,实现类负责“具体怎么做”:

text
页面 -> MessageService 接口 -> LocalMessageService 具体实现
                         \-> 测试实现或网络实现

queryMessages(): Promise<string[]> 是双方共同遵守的契约。只要新实现满足这个签名,页面就可以替换数据源,而不需要修改加载状态和 UI 渲染逻辑。

最小 ArkTS / ArkUI 示例

ts
interface MessageService {
  queryMessages(): Promise<string[]>;
}

class LocalMessageService implements MessageService {
  queryMessages(): Promise<string[]> {
    return Promise.resolve(['系统通知', '学习提醒']);
  }
}

@Entry
@Component
struct MessagePage {
  private messageService: MessageService = new LocalMessageService();

  @State loading: boolean = false;
  @State items: string[] = [];

  aboutToAppear(): void {
    this.loadMessages();
  }

  async loadMessages(): Promise<void> {
    this.loading = true;
    try {
      this.items = await this.messageService.queryMessages();
    } finally {
      this.loading = false;
    }
  }

  build() {
    Column({ space: 12 }) {
      if (this.loading) {
        Text('加载中...')
      } else {
        ForEach(this.items, (item: string) => {
          Text(item)
        }, (item: string) => item)
      }
    }
    .width('100%')
    .padding(20)
  }
}

页面字段的类型是 MessageService,而不是 LocalMessageService。这表示页面只使用接口承诺的能力;数据来自本地、网络还是测试数据,由传入的具体实现决定。

3~5 分钟练习

新增一个 EmptyMessageService:

  1. 实现 MessageService 接口。
  2. queryMessages() 返回空数组。
  3. 把页面中的服务替换为该实现,观察列表变为空。

参考答案

ts
class EmptyMessageService implements MessageService {
  queryMessages(): Promise<string[]> {
    return Promise.resolve([]);
  }
}

页面中只替换初始化语句:

ts
private messageService: MessageService = new EmptyMessageService();

页面的生命周期、状态更新和 UI 代码均无需改变,这就是依赖接口带来的可替换性。

与上一课的联系

上一课确定了“页面负责状态与渲染,服务负责取数”的职责边界;本课用接口进一步固定这条边界,使具体数据服务可以替换。下一步可以学习为数据服务编写简单的单元测试,验证成功结果和失败行为。