TypeScript 类的核心概念详解
1. 抽象类(Abstract Class)
定义
抽象类是一种不能被直接实例化的特殊类,只能被其他类继承。它可以包含抽象方法(没有具体实现的方法)和具体方法。
用途
- 作为基类提供通用功能
- 定义接口规范
- 强制子类实现特定方法
- 共享公共代码
何时使用
- 当多个类有共同的基础功能时
- 需要强制子类实现某些方法时
- 想要防止类被直接实例化时
abstract class Animal {
// 抽象方法:必须在子类中实现
abstract makeSound(): void;
// 具体方法:提供通用实现
move(): void {
console.log('Moving...');
}
}
class Dog extends Animal {
makeSound(): void {
console.log('Woof!');
}
}
2. 静态成员(Static Members)
定义
静态成员属于类本身而不是类的实例,可以直接通过类名访问。
用途
- 存储类级别的数据
- 提供工具方法
- 实现单例模式
- 缓存数据
何时使用
- 需要在所有实例间共享数据时
- 不需要访问实例数据的工具方法
- 需要计数器或缓存时
class Database {
// 静态属性:所有实例共享
private static instance: Database;
private static connectionCount: number = 0;
// 静态方法:不需要实例化就能调用
static getInstance(): Database {
if (!Database.instance) {
Database.instance = new Database();
}
return Database.instance;
}
// 静态方法可以访问静态属性
static getConnectionCount(): number {
return Database.connectionCount;
}
}
3. 访问修饰符(Access Modifiers)
定义
访问修饰符控制类成员的可访问性和可见性。
种类和作用域
- public(默认)
- 定义:可以在任何地方访问
- 作用域:类内部、类实例、子类、外部代码
- 用途:定义公共 API
- private
- 定义:只能在声明的类内部访问
- 作用域:仅类内部
- 用途:隐藏内部实现细节
- protected
- 定义:可以在声明的类及其子类中访问
- 作用域:类内部和子类
- 用途:允许子类访问基类功能
何时使用各种修饰符
- 使用 public 当:
- 需要对外暴露 API
- 属性/方法需要在类外部访问
- 是公共接口的一部分
- 使用 private 当:
- 需要隐藏实现细节
- 防止外部直接修改状态
- 需要严格控制访问
- 使用 protected 当:
- 需要在继承链中共享功能
- 子类需要访问父类的某些功能
- 想要限制外部访问但允许子类访问
class BankAccount {
// public:对外可见的 API
public accountNumber: string;
// private:内部实现细节
private balance: number;
// protected:允许子类访问
protected transactionHistory: Transaction[];
constructor(accountNumber: string) {
this.accountNumber = accountNumber;
this.balance = 0;
this.transactionHistory = [];
}
// public 方法:对外 API
public deposit(amount: number): void {
this.updateBalance(amount);
}
// private 方法:内部实现
private updateBalance(amount: number): void {
this.balance += amount;
this.logTransaction(amount);
}
// protected 方法:子类可用
protected logTransaction(amount: number): void {
this.transactionHistory.push({
amount,
date: new Date()
});
}
}
4. 属性修饰符(Property Modifiers)
readonly
- 定义:只能在声明时或构造函数中赋值
- 用途:防止属性被修改
- 何时使用:常量、配置值、不可变数据
class Config {
readonly API_KEY: string;
readonly MAX_RETRIES: number = 3;
constructor(apiKey: string) {
this.API_KEY = apiKey; // 只能在这里赋值
}
}
可选属性(?)
- 定义:属性可以不存在
- 用途:表示可选的类成员
- 何时使用:处理可选配置、部分初始化
class UserProfile {
name: string;
age?: number; // 可选属性
bio?: string; // 可选属性
}
5. 方法修饰符
abstract
- 定义:在抽象类中声明但不实现的方法
- 用途:强制子类提供实现
- 何时使用:需要确保子类实现特定行为时
abstract class Shape {
abstract calculateArea(): number; // 子类必须实现
abstract calculatePerimeter(): number; // 子类必须实现
// 具体方法可以使用抽象方法
printDetails(): void {
console.log(`Area: ${this.calculateArea()}`);
console.log(`Perimeter: ${this.calculatePerimeter()}`);
}
}
override
- 定义:明确指示方法重写父类方法
- 用途:增加代码可读性,防止意外重写
- 何时使用:有意重写父类方法时
class Parent {
greet(): void {
console.log("Hello");
}
}
class Child extends Parent {
override greet(): void { // 明确表示重写
console.log("Hi there");
}
}
最佳实践总��
- 封装原则
- 默认使用 private
- 只有需要时才改为 protected 或 public
- 使用访问器方法控制属性访问
- 继承设计
- 优先使用组合而不是继承
- 抽象类用于定义契约
- 使用 protected 而不是 public 共享功能
- 静态成员使用
- 用于工具方法和共享状态
- 避免过度使用静态成员
- 考虑使用单例模式替代静态类
- 修饰符选择
- 明确每个成员的可见性需求
- 使用 readonly 保护不可变数据
- 合理使用可选属性处理可选状态