鸿蒙学习实战之路:ArkTS基础接口与类定义

ArkTS基础接口与类定义

文章概述

本文是ArkTS语言的基础教程,重点讲解在HarmonyOS应用开发中如何使用ArkTS定义类、接口以及相关的面向对象编程概念。通过本文,您将掌握ArkTS的核心语法特性,为构建复杂的HarmonyOS应用打下坚实基础。

官方参考资料:

基础概念

什么是ArkTS?

ArkTS是HarmonyOS优选的应用开发语言,它在TypeScript的基础上,扩展了声明式UI、状态管理等能力。

主要特性:

  • 静态类型检查
  • 面向对象编程支持
  • 声明式UI描述
  • 状态驱动UI更新
  • 与HarmonyOS API深度集成

环境要求

开发环境配置:

  • DevEco Studio 4.0或更高版本
  • HarmonyOS SDK API 9或更高版本
  • 推荐使用Node.js 16.x或18.x

类定义基础

基本类定义

在ArkTS中,使用class关键字定义类,类可以包含属性、构造器和方法。

// 基础类定义示例
class Person {
  // 类属性
  name: string
  age: number
  
  // 构造器
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
  
  // 类方法
  introduce(): string {
    return `大家好,我是${this.name},今年${this.age}岁。`
  }
  
  // 带参数的方法
  celebrateBirthday(): void {
    this.age++
    console.log(`${this.name}过生日啦!现在${this.age}岁。`)
  }
}

// 使用示例
@Entry
@Component
struct ClassExample {
  build() {
    Column() {
      Button('创建Person实例')
        .onClick(() => {
          let person = new Person('张三', 25)
          console.log(person.introduce())
          person.celebrateBirthday()
        })
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

构造器参数属性

ArkTS支持在构造器参数中直接定义属性,这是定义类的简洁方式。

// 使用构造器参数属性
class Student {
  // 直接在构造器参数中定义属性
  constructor(
    public name: string,
    public studentId: string,
    private grade: number = 1  // 默认参数
  ) {}
  
  getStudentInfo(): string {
    return `学生:${this.name},学号:${this.studentId},年级:${this.grade}`
  }
  
  promote(): void {
    this.grade++
    console.log(`${this.name}升到${this.grade}年级`)
  }
}

// 使用示例
@Entry
@Component
struct StudentExample {
  build() {
    Column() {
      Button('创建学生')
        .onClick(() => {
          let student = new Student('李四', '2024001')
          console.log(student.getStudentInfo())
          student.promote()
        })
    }
    .width('100%')
    .height('100%')
  }
}

接口定义与应用

基础接口定义

接口用于定义对象的形状,确保类实现特定的结构。

// 定义接口
interface Animal {
  name: string
  age: number
  makeSound(): void
  move(): void
}

// 实现接口的类
class Dog implements Animal {
  name: string
  age: number
  breed: string
  
  constructor(name: string, age: number, breed: string) {
    this.name = name
    this.age = age
    this.breed = breed
  }
  
  makeSound(): void {
    console.log(`${this.name}在汪汪叫!`)
  }
  
  move(): void {
    console.log(`${this.name}在奔跑`)
  }
  
  // 类特有的方法
  fetch(): void {
    console.log(`${this.name}在接飞盘`)
  }
}

class Cat implements Animal {
  name: string
  age: number
  color: string
  
  constructor(name: string, age: number, color: string) {
    this.name = name
    this.age = age
    this.color = color
  }
  
  makeSound(): void {
    console.log(`${this.name}在喵喵叫!`)
  }
  
  move(): void {
    console.log(`${this.name}在优雅地走路`)
  }
  
  climbTree(): void {
    console.log(`${this.name}在爬树`)
  }
}

可选属性和只读属性

接口支持可选属性和只读属性,提供更灵活的类型定义。

// 包含可选和只读属性的接口
interface Vehicle {
  readonly id: string        // 只读属性
  brand: string
  model: string
  year?: number             // 可选属性
  start(): void
  stop(): void
}

class Car implements Vehicle {
  readonly id: string
  brand: string
  model: string
  year?: number
  
  constructor(id: string, brand: string, model: string, year?: number) {
    this.id = id
    this.brand = brand
    this.model = model
    this.year = year
  }
  
  start(): void {
    console.log(`${this.brand} ${this.model} 启动`)
  }
  
  stop(): void {
    console.log(`${this.brand} ${this.model} 停止`)
  }
  
  // 尝试修改只读属性会报错
  // updateId(newId: string): void {
  //   this.id = newId  // 编译错误:无法分配到"id",因为它是只读属性
  // }
}

继承与多态

类继承

ArkTS支持类的单继承,使用extends关键字。

// 基类
class Shape {
  color: string
  protected position: { x: number, y: number }  // 受保护属性
  
  constructor(color: string, x: number = 0, y: number = 0) {
    this.color = color
    this.position = { x, y }
  }
  
  // 基础方法
  move(x: number, y: number): void {
    this.position.x = x
    this.position.y = y
    console.log(`图形移动到位置 (${x}, ${y})`)
  }
  
  // 抽象方法(在TypeScript中需要使用abstract关键字,但ArkTS基于TS)
  getArea(): number {
    return 0
  }
  
  describe(): string {
    return `这是一个${this.color}的图形`
  }
}

// 派生类
class Circle extends Shape {
  radius: number
  
  constructor(color: string, radius: number, x: number = 0, y: number = 0) {
    super(color, x, y)  // 调用父类构造器
    this.radius = radius
  }
  
  // 重写父类方法
  getArea(): number {
    return Math.PI * this.radius * this.radius
  }
  
  describe(): string {
    return `${super.describe()},是一个半径为${this.radius}的圆形,面积:${this.getArea().toFixed(2)}`
  }
  
  // 子类特有方法
  getCircumference(): number {
    return 2 * Math.PI * this.radius
  }
}

class Rectangle extends Shape {
  width: number
  height: number
  
  constructor(color: string, width: number, height: number, x: number = 0, y: number = 0) {
    super(color, x, y)
    this.width = width
    this.height = height
  }
  
  getArea(): number {
    return this.width * this.height
  }
  
  describe(): string {
    return `${super.describe()},是一个${this.width}x${this.height}的矩形,面积:${this.getArea()}`
  }
  
  // 子类特有方法
  isSquare(): boolean {
    return this.width === this.height
  }
}

多态应用

@Entry
@Component
struct ShapeExample {
  build() {
    Column() {
      Button('多态演示')
        .onClick(() => {
          // 多态:父类引用指向子类对象
          let shapes: Shape[] = [
            new Circle('红色', 5),
            new Rectangle('蓝色', 4, 6),
            new Circle('绿色', 3)
          ]
          
          shapes.forEach(shape => {
            console.log(shape.describe())
          })
        })
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

访问控制修饰符

ArkTS提供了三种访问控制修饰符,用于控制类成员的可见性。

修饰符 类内部 子类 类外部 描述
public 默认修饰符,任何地方都可访问
private 仅在类内部可访问
protected 类内部和子类可访问
class BankAccount {
  public readonly accountNumber: string
  private _balance: number = 0
  protected owner: string
  
  constructor(accountNumber: string, owner: string, initialBalance: number = 0) {
    this.accountNumber = accountNumber
    this.owner = owner
    this._balance = initialBalance
  }
  
  // 公共方法 - 可以外部调用
  public deposit(amount: number): void {
    if (amount > 0) {
      this._balance += amount
      console.log(`存入${amount}元,当前余额:${this._balance}元`)
    }
  }
  
  public withdraw(amount: number): boolean {
    if (amount > 0 && this._balance >= amount) {
      this._balance -= amount
      console.log(`取出${amount}元,当前余额:${this._balance}元`)
      return true
    }
    console.log('取款失败:余额不足或金额无效')
    return false
  }
  
  // 私有方法 - 只能在类内部使用
  private validateAmount(amount: number): boolean {
    return amount > 0 && amount <= 1000000
  }
  
  // 受保护方法 - 子类可以访问
  protected updateOwner(newOwner: string): void {
    this.owner = newOwner
    console.log(`账户持有人变更为:${newOwner}`)
  }
  
  // 公开的getter方法
  public get balance(): number {
    return this._balance
  }
}

// 继承示例
class SavingsAccount extends BankAccount {
  private interestRate: number
  
  constructor(accountNumber: string, owner: string, interestRate: number) {
    super(accountNumber, owner)
    this.interestRate = interestRate
  }
  
  // 可以访问父类的protected成员
  transferOwnership(newOwner: string): void {
    this.updateOwner(newOwner)  // 可以调用protected方法
  }
  
  // 无法访问父类的private成员
  // showPrivateBalance(): void {
  //   console.log(this._balance)  // 编译错误:_balance是私有的
  // }
  
  addInterest(): void {
    const interest = this.balance * this.interestRate  // 通过public getter访问
    this.deposit(interest)
    console.log(`添加利息:${interest.toFixed(2)}元`)
  }
}

@Entry
@Component
struct BankExample {
  build() {
    Column() {
      Button('银行账户演示')
        .onClick(() => {
          let account = new SavingsAccount('123456789', '王五', 0.05)
          account.deposit(1000)
          account.addInterest()
          console.log(`当前余额:${account.balance}元`)
          
          // 以下操作会报错:
          // account._balance = 9999  // 错误:_balance是私有的
          // account.updateOwner('赵六')  // 错误:updateOwner是受保护的
        })
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

静态成员

静态成员属于类本身,而不是类的实例。

class MathUtils {
  // 静态属性
  static readonly PI: number = 3.14159
  static readonly VERSION: string = '1.0.0'
  
  // 静态方法
  static calculateCircleArea(radius: number): number {
    return this.PI * radius * radius
  }
  
  static calculateDistance(x1: number, y1: number, x2: number, y2: number): number {
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
  }
  
  static getVersion(): string {
    return `数学工具库版本:${this.VERSION}`
  }
}

class Counter {
  private static instanceCount: number = 0
  private static _totalCount: number = 0
  
  public readonly id: number
  
  constructor() {
    Counter.instanceCount++
    this.id = Counter.instanceCount
  }
  
  // 静态getter
  static get totalInstances(): number {
    return this.instanceCount
  }
  
  static get totalCount(): number {
    return this._totalCount
  }
  
  increment(): void {
    Counter._totalCount++
    console.log(`计数器${this.id}增加,总计:${Counter._totalCount}`)
  }
  
  decrement(): void {
    if (Counter._totalCount > 0) {
      Counter._totalCount--
      console.log(`计数器${this.id}减少,总计:${Counter._totalCount}`)
    }
  }
}

@Entry
@Component
struct StaticExample {
  build() {
    Column() {
      Button('静态成员演示')
        .onClick(() => {
          // 使用静态方法,不需要创建实例
          console.log(`PI值:${MathUtils.PI}`)
          console.log(`半径为5的圆面积:${MathUtils.calculateCircleArea(5).toFixed(2)}`)
          console.log(MathUtils.getVersion())
          
          // 计数器实例演示
          let counter1 = new Counter()
          let counter2 = new Counter()
          
          counter1.increment()
          counter2.increment()
          counter1.increment()
          counter1.decrement()
          
          console.log(`创建的计数器实例数:${Counter.totalInstances}`)
          console.log(`总计数值:${Counter.totalCount}`)
        })
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

抽象类和接口的高级用法

抽象类

抽象类不能实例化,只能被继承,可以包含抽象方法和具体实现。

// 抽象类
abstract class Notification {
  protected recipient: string
  protected message: string
  
  constructor(recipient: string, message: string) {
    this.recipient = recipient
    this.message = message
  }
  
  // 抽象方法 - 必须由子类实现
  abstract send(): boolean
  
  // 具体方法 - 子类可以继承使用
  protected formatMessage(): string {
    return `给 ${this.recipient} 的消息:${this.message}`
  }
  
  // 模板方法模式
  processNotification(): void {
    console.log('开始处理通知...')
    const success = this.send()
    if (success) {
      console.log('通知发送成功')
      this.logNotification()
    } else {
      console.log('通知发送失败')
    }
  }
  
  private logNotification(): void {
    console.log(`通知记录:${new Date().toISOString()} - ${this.formatMessage()}`)
  }
}

// 具体实现类
class EmailNotification extends Notification {
  private emailAddress: string
  
  constructor(recipient: string, message: string, emailAddress: string) {
    super(recipient, message)
    this.emailAddress = emailAddress
  }
  
  send(): boolean {
    console.log(`发送邮件到:${this.emailAddress}`)
    console.log(`邮件内容:${this.formatMessage()}`)
    // 模拟发送逻辑
    return Math.random() > 0.2  // 80%成功率
  }
}

class SMSNotification extends Notification {
  private phoneNumber: string
  
  constructor(recipient: string, message: string, phoneNumber: string) {
    super(recipient, message)
    this.phoneNumber = phoneNumber
  }
  
  send(): boolean {
    console.log(`发送短信到:${this.phoneNumber}`)
    console.log(`短信内容:${this.message}`)  // 短信通常较短,不使用完整格式
    // 模拟发送逻辑
    return Math.random() > 0.3  // 70%成功率
  }
}

接口继承

接口可以继承其他接口,实现接口的组合。

// 基础接口
interface Identifiable {
  readonly id: string
  createdAt: Date
}

interface Timestampable {
  updatedAt: Date
  updateTimestamp(): void
}

// 接口继承
interface User extends Identifiable, Timestampable {
  username: string
  email: string
  isActive: boolean
  activate(): void
  deactivate(): void
}

// 实现复合接口
class SystemUser implements User {
  readonly id: string
  createdAt: Date
  updatedAt: Date
  username: string
  email: string
  isActive: boolean = true
  
  constructor(id: string, username: string, email: string) {
    this.id = id
    this.username = username
    this.email = email
    this.createdAt = new Date()
    this.updatedAt = new Date()
  }
  
  updateTimestamp(): void {
    this.updatedAt = new Date()
    console.log(`用户 ${this.username} 时间戳已更新`)
  }
  
  activate(): void {
    this.isActive = true
    this.updateTimestamp()
    console.log(`用户 ${this.username} 已激活`)
  }
  
  deactivate(): void {
    this.isActive = false
    this.updateTimestamp()
    console.log(`用户 ${this.username} 已停用`)
  }
  
  getUserInfo(): string {
    return `用户ID:${this.id},用户名:${this.username},状态:${this.isActive ? '活跃' : '停用'}`
  }
}

实际应用案例:HarmonyOS UI组件类

下面展示如何在HarmonyOS应用中使用ArkTS类来管理UI状态。

// 定义数据模型类
class TodoItem {
  constructor(
    public id: string,
    public title: string,
    public completed: boolean = false,
    public createdAt: Date = new Date()
  ) {}
  
  toggleComplete(): void {
    this.completed = !this.completed
  }
  
  updateTitle(newTitle: string): void {
    this.title = newTitle
  }
}

// 定义状态管理类
@Observed
class TodoList {
  private items: TodoItem[] = []
  
  addItem(title: string): void {
    const newItem = new TodoItem(
      Date.now().toString(),
      title
    )
    this.items.push(newItem)
  }
  
  removeItem(id: string): void {
    this.items = this.items.filter(item => item.id !== id)
  }
  
  toggleItem(id: string): void {
    const item = this.items.find(item => item.id === id)
    if (item) {
      item.toggleComplete()
    }
  }
  
  get completedCount(): number {
    return this.items.filter(item => item.completed).length
  }
  
  get totalCount(): number {
    return this.items.length
  }
  
  getItems(): TodoItem[] {
    return [...this.items]  // 返回副本
  }
}

@Entry
@Component
struct TodoApp {
  @State todoList: TodoList = new TodoList()
  @State newItemTitle: string = ''
  
  build() {
    Column({ space: 20 }) {
      Text('待办事项')
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
      
      Text(`总计:${this.todoList.totalCount},已完成:${this.todoList.completedCount}`)
        .fontSize(16)
      
      TextInput({ placeholder: '输入新事项' })
        .width('90%')
        .onChange((value: string) => {
          this.newItemTitle = value
        })
      
      Button('添加事项')
        .width('50%')
        .onClick(() => {
          if (this.newItemTitle.trim()) {
            this.todoList.addItem(this.newItemTitle)
            this.newItemTitle = ''
          }
        })
      
      List({ space: 10 }) {
        ForEach(this.todoList.getItems(), (item: TodoItem) => {
          ListItem() {
            Row({ space: 10 }) {
              Text(item.title)
                .fontSize(18)
                .decoration({ type: item.completed ? TextDecorationType.LineThrough : TextDecorationType.None })
              
              Checkbox()
                .select(item.completed)
                .onChange((checked: boolean) => {
                  this.todoList.toggleItem(item.id)
                })
              
              Button('删除')
                .onClick(() => {
                  this.todoList.removeItem(item.id)
                })
            }
            .width('100%')
            .justifyContent(FlexAlign.SpaceBetween)
          }
        }, (item: TodoItem) => item.id)
      }
      .layoutWeight(1)
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

重要注意事项

版本兼容性

API级别说明:

  • 本文代码基于HarmonyOS API 9编写
  • 确保您的DevEco Studio和SDK版本兼容
  • 部分高级特性可能需要更高API级别

常见陷阱与解决方案

1. 构造器中的属性初始化

// 错误示例
class ProblemClass {
  name: string
  // 忘记在构造器中初始化name
  
  constructor() {
    // 没有初始化name
  }
}

// 正确做法
class CorrectClass {
  name: string = ''  // 提供默认值
  
  constructor(name?: string) {
    if (name) {
      this.name = name
    }
  }
}

2. 接口实现完整性

interface RequiredMethods {
  method1(): void
  method2(): string
}

// 错误:没有实现所有接口方法
// class IncompleteClass implements RequiredMethods {
//   method1(): void { }
//   // 缺少method2
// }

// 正确:实现所有接口方法
class CompleteClass implements RequiredMethods {
  method1(): void { }
  method2(): string { return '' }
}

3. 访问控制注意事项

class AccessExample {
  private secret: string = '机密信息'
  
  // 正确:通过公共方法访问私有属性
  getSecret(): string {
    return this.secret
  }
}

let example = new AccessExample()
// console.log(example.secret)  // 错误:secret是私有的
console.log(example.getSecret())  // 正确:通过公共方法访问

性能优化建议

1. 避免过度使用继承

  • 优先使用组合而非继承
  • 保持继承层次简单(建议不超过3层)

2. 合理使用访问控制

  • 将属性设置为private,通过方法控制访问
  • 使用protected允许子类扩展,同时限制外部访问

3. 静态成员的使用场景

  • 工具类方法适合作为静态方法
  • 常量值适合作为静态属性
  • 避免在静态方法中保存状态

总结

通过本文的学习,您应该已经掌握了ArkTS中类和接口的核心概念:

  • 类定义:使用class关键字,包含属性、构造器和方法
  • 接口:定义对象结构,确保实现一致性
  • 继承:使用extends实现代码复用
  • 访问控制:public、private、protected控制可见性
  • 静态成员:属于类本身的属性和方法
  • 抽象类:提供基础框架,要求子类实现特定方法

这些面向对象编程的概念是构建复杂HarmonyOS应用的基础。在实际开发中,合理运用这些特性可以提高代码的可维护性、可扩展性和重用性。

下一步学习建议:

  • 深入学习ArkTS的泛型编程
  • 掌握装饰器在HarmonyOS中的应用
  • 学习状态管理和数据绑定的高级用法
  • 实践更多HarmonyOS UI组件与ArkTS类的结合使用

继续探索ArkTS的强大功能,构建出色的HarmonyOS应用!

需要参加鸿蒙认证的请点击 鸿蒙认证链接

posted @ 2025-11-26 17:03  时间煮鱼  阅读(21)  评论(0)    收藏  举报