ArkTS基礎接口與類定義
文章概述
本文是ArkTS語言的基礎教程,重點講解在HarmonyOS應用開發中如何使用ArkTS定義類、接口以及相關的面向對象編程概念。通過本文,您將掌握ArkTS的核心語法特性,為構建複雜的HarmonyOS應用打下堅實基礎。
官方參考資料:
- ArkTS語言官方文檔
- HarmonyOS應用開發指南
- ArkTS API參考
基礎概念
什麼是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提供了三種訪問控制修飾符,用於控制類成員的可見性。
|
修飾符
|
類內部
|
子類
|
類外部
|
描述
|
|
|
✅
|
✅
|
✅
|
默認修飾符,任何地方都可訪問
|
|
|
✅
|
❌
|
❌
|
僅在類內部可訪問
|
|
|
✅
|
✅
|
❌
|
類內部和子類可訪問
|
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應用!