第一章:ArkTS面向对象编程——从基础到实战
大家好,我是老张。今天咱们聊聊ArkTS的面向对象编程。说实话,很多初学者觉得面向对象就是个概念,背背定义就完事了。但我在鸿蒙项目里踩过不少坑,才真正理解——面向对象不是理论,是帮你管理复杂代码的工具。
ArkTS基于TypeScript,但做了不少鸿蒙特有的优化。咱们直接上干货。
1. 类的定义:从最简单的开始
先看一个最基础的类定义。我个人习惯把类当作“模板”,用来创建对象。
class Person {
name: string = ''
age: number = 0
constructor(name: string, age: number) {
this.name = name
this.age = age
}
sayHello(): void {
console.log(`你好,我是${this.name},今年${this.age}岁`)
}
}
let p = new Person('张三', 25)
p.sayHello()
这里要注意几点:
- 属性必须初始化,或者用
!声明非空。我刚开始写ArkTS时老忘,编译器直接报错。 constructor是构造函数,创建对象时自动调用。- 方法里用
this访问当前实例的属性。
constructor(name: string, age?: number),这样age可以不传。
3. 继承:别重复造轮子
继承是面向对象的核心之一。说白了,就是子类复用父类的代码。
class Student extends Person {
grade: number = 0
constructor(name: string, age: number, grade: number) {
super(name, age) // 调用父类构造函数
this.grade = grade
}
study(): void {
console.log(`${this.name}正在学习,年级:${this.grade}`)
}
}
let stu = new Student('李四', 20, 3)
stu.sayHello() // 继承自父类
stu.study() // 子类自己的方法
嗯,这里有个坑。我曾经在项目里忘了调用super(),结果子类属性全是undefined。记住:子类构造函数里,super()必须写在第一行。
3. 接口:定义契约
接口是什么?你可以把它理解成一份“合同”。谁实现了这个接口,就必须遵守里面的规则。
interface Flyable {
fly(): void
land(): void
}
class Bird implements Flyable {
fly(): void {
console.log('鸟儿在飞')
}
land(): void {
console.log('鸟儿着陆')
}
}
class Airplane implements Flyable {
fly(): void {
console.log('飞机起飞')
}
land(): void {
console.log('飞机降落')
}
}
你想想看,如果没有接口,每个类自己定义方法名,调用方得多痛苦?接口统一了行为规范。
我在项目中经常用接口来定义数据模型。比如网络请求返回的数据结构,用接口约束好,后面处理起来特别清晰。
4. 泛型:让代码更灵活
泛型,说白了就是“类型参数”。写一个函数或类,可以处理多种类型,而不是写死。
// 泛型函数
function identity<T>(arg: T): T {
return arg
}
let result1 = identity<number>(42)
let result2 = identity<string>('hello')
// 泛型类
class Box<T> {
private content: T
constructor(content: T) {
this.content = content
}
getContent(): T {
return this.content
}
}
let numberBox = new Box<number>(123)
let stringBox = new Box<string>('abc')
为什么会用到泛型?举个例子。我做过一个缓存工具,要存各种类型的数据。没有泛型的话,要么用any(失去类型检查),要么每种类型写一个类(代码爆炸)。泛型完美解决了这个问题。
<T>只是一个占位符,你可以用任何字母,但业界习惯用T、K、V。
5. 模块化:import/export
模块化是大型项目的基石。ArkTS支持ES Module语法,用export导出,import导入。
// math.ts
export function add(a: number, b: number): number {
return a + b
}
export const PI = 3.14159
export class Calculator {
multiply(a: number, b: number): number {
return a * b
}
}
// main.ts
import { add, PI, Calculator } from './math'
console.log(add(1, 2))
console.log(PI)
let calc = new Calculator()
console.log(calc.multiply(3, 4))
我个人习惯用命名导出(就是带花括号那种)。默认导出虽然方便,但重构时容易出问题。
export default和export混用,结果导入时搞不清要不要加花括号。后来统一用命名导出,再也没出过问题。
6. 综合实战:一个简单的用户管理系统
咱们把今天学的知识串起来,写个小例子。
// 定义接口
interface User {
id: number
name: string
email: string
}
// 泛型仓库
class Repository<T> {
private items: T[] = []
add(item: T): void {
this.items.push(item)
}
getAll(): T[] {
return this.items
}
find(predicate: (item: T) => boolean): T | undefined {
return this.items.find(predicate)
}
}
// 继承扩展
class UserRepository extends Repository<User> {
findByEmail(email: string): User | undefined {
return this.find(user => user.email === email)
}
}
// 使用
let userRepo = new UserRepository()
userRepo.add({ id: 1, name: '张三', email: 'zhangsan@example.com' })
userRepo.add({ id: 2, name: '李四', email: 'lisi@example.com' })
console.log(userRepo.findByEmail('lisi@example.com'))
这个例子涵盖了类、继承、接口、泛型、模块化(虽然没展示导入导出,但实际项目里每个类可以单独一个文件)。
嗯,到这里第一章的内容就差不多了。面向对象编程不是一蹴而就的,需要在实际项目中慢慢体会。下一章咱们会深入ArkTS的高级特性,包括装饰器、异步编程等。
记住:写代码不是炫技,是解决问题。面向对象只是工具,用好了事半功倍。
公众号:蓝海资料掘金营,微信deep3321