抽象类与抽象方法
抽象类与抽象方法的基本概念
抽象类是一种特殊的类,它不能被实例化,只能被继承。抽象类中可以包含抽象方法,这些方法只有声明没有实现,必须在子类中被具体实现。抽象类的主要作用是定义一组公共的接口和行为规范,强制子类遵循特定的结构。
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log("Moving...");
}
}
抽象类的特点
抽象类与普通类有几个关键区别:
- 抽象类必须使用
abstract
关键字声明 - 抽象类不能直接实例化
- 抽象类可以包含抽象方法和具体实现的方法
- 抽象类可以有构造函数
- 抽象类可以包含成员变量
abstract class Department {
constructor(public name: string) {}
abstract printMeeting(): void;
printName(): void {
console.log("Department name: " + this.name);
}
}
抽象方法的特性
抽象方法是抽象类中的核心概念,具有以下特点:
- 必须使用
abstract
关键字标记 - 不能有具体实现(没有方法体)
- 必须在派生类中实现
- 可以包含参数和返回类型声明
- 访问修饰符可以是public、protected或private
abstract class Shape {
abstract getArea(): number;
abstract getPerimeter(): number;
displayInfo(): void {
console.log(`Area: ${this.getArea()}, Perimeter: ${this.getPerimeter()}`);
}
}
实现抽象类的子类
当继承抽象类时,子类必须实现所有抽象方法,否则子类也必须声明为抽象类。
class Circle extends Shape {
constructor(private radius: number) {
super();
}
getArea(): number {
return Math.PI * this.radius * this.radius;
}
getPerimeter(): number {
return 2 * Math.PI * this.radius;
}
}
const circle = new Circle(5);
circle.displayInfo(); // 输出: Area: 78.53981633974483, Perimeter: 31.41592653589793
抽象类与接口的区别
虽然抽象类和接口在某些方面相似,但它们有重要区别:
特性 | 抽象类 | 接口 |
---|---|---|
实现 | 可以包含具体实现 | 只有声明 |
成员变量 | 可以有 | 不能有 |
构造函数 | 可以有 | 不能有 |
多重继承 | 不支持 | 支持 |
访问修饰符 | 可以有 | 默认public |
// 接口示例
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
// 抽象类示例
abstract class ClockAbstract {
abstract currentTime: Date;
abstract setTime(d: Date): void;
getTime(): Date {
return this.currentTime;
}
}
抽象类的实际应用场景
抽象类特别适合以下场景:
- 定义框架或库的基础结构
- 强制派生类实现特定方法
- 提供部分通用实现
- 创建具有共同行为的类家族
abstract class DataAccess<T> {
abstract connect(): Promise<void>;
abstract disconnect(): Promise<void>;
abstract query(sql: string): Promise<T[]>;
async executeTransaction(queries: string[]): Promise<void> {
try {
await this.connect();
for (const query of queries) {
await this.query(query);
}
} finally {
await this.disconnect();
}
}
}
class MySQLAccess extends DataAccess<any> {
async connect(): Promise<void> { /* MySQL连接实现 */ }
async disconnect(): Promise<void> { /* MySQL断开连接实现 */ }
async query(sql: string): Promise<any[]> { /* MySQL查询实现 */ }
}
抽象类中的构造函数
抽象类可以有构造函数,虽然不能直接实例化抽象类,但子类可以通过super()
调用父类的构造函数。
abstract class Person {
constructor(protected name: string, protected age: number) {}
abstract introduce(): string;
}
class Employee extends Person {
constructor(name: string, age: number, private jobTitle: string) {
super(name, age);
}
introduce(): string {
return `Hi, I'm ${this.name}, ${this.age} years old, working as ${this.jobTitle}`;
}
}
const emp = new Employee("Alice", 30, "Developer");
console.log(emp.introduce());
抽象属性
除了抽象方法,TypeScript还支持抽象属性,这些属性必须在派生类中实现。
abstract class Vehicle {
abstract brand: string;
abstract model: string;
abstract year: number;
getFullDescription(): string {
return `${this.year} ${this.brand} ${this.model}`;
}
}
class Car extends Vehicle {
brand = "Toyota";
model = "Camry";
year = 2020;
}
const myCar = new Car();
console.log(myCar.getFullDescription()); // 输出: 2020 Toyota Camry
抽象类与多态
抽象类是实现多态的重要方式,通过抽象类定义的接口,可以在运行时决定调用哪个具体实现。
abstract class PaymentProcessor {
abstract processPayment(amount: number): boolean;
}
class CreditCardProcessor extends PaymentProcessor {
processPayment(amount: number): boolean {
console.log(`Processing credit card payment of $${amount}`);
return true;
}
}
class PayPalProcessor extends PaymentProcessor {
processPayment(amount: number): boolean {
console.log(`Processing PayPal payment of $${amount}`);
return true;
}
}
function handlePayment(processor: PaymentProcessor, amount: number) {
processor.processPayment(amount);
}
const creditCard = new CreditCardProcessor();
const paypal = new PayPalProcessor();
handlePayment(creditCard, 100); // Processing credit card payment of $100
handlePayment(paypal, 50); // Processing PayPal payment of $50
抽象类与设计模式
抽象类在许多设计模式中扮演重要角色,如模板方法模式、工厂方法模式等。
// 模板方法模式示例
abstract class DataExporter {
// 模板方法
export(): void {
this.prepareData();
this.validateData();
this.sendData();
this.cleanup();
}
protected abstract prepareData(): void;
protected abstract validateData(): void;
protected sendData(): void {
console.log("Sending data to server...");
}
protected cleanup(): void {
console.log("Cleaning up temporary files...");
}
}
class CSVExporter extends DataExporter {
protected prepareData(): void {
console.log("Preparing CSV data...");
}
protected validateData(): void {
console.log("Validating CSV data...");
}
}
const exporter = new CSVExporter();
exporter.export();
抽象类的局限性
虽然抽象类很强大,但也有其局限性:
- TypeScript是单继承语言,一个类只能继承一个抽象类
- 抽象类增加了层级关系,可能使代码结构复杂
- 过度使用抽象类可能导致设计过度工程化
// 单继承限制示例
abstract class A {
abstract methodA(): void;
}
abstract class B {
abstract methodB(): void;
}
// 错误:不能同时继承A和B
class C extends A /*, B*/ {
methodA(): void { /* 实现 */ }
// methodB(): void { /* 无法同时实现 */ }
}
抽象类与混入(Mixins)
虽然TypeScript不支持多重继承,但可以通过混入模式模拟从多个抽象类继承行为。
// 混入模式示例
class Disposable {
isDisposed: boolean = false;
dispose() { this.isDisposed = true; }
}
class Activatable {
isActive: boolean = false;
activate() { this.isActive = true; }
deactivate() { this.isActive = false; }
}
// 使用混入
class SmartObject implements Disposable, Activatable {
constructor() {
setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);
}
// Disposable
isDisposed: boolean = false;
dispose: () => void;
// Activatable
isActive: boolean = false;
activate: () => void;
deactivate: () => void;
}
applyMixins(SmartObject, [Disposable, Activatable]);
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name];
});
});
}
抽象类与依赖注入
抽象类常用于依赖注入场景,作为服务契约定义接口。
abstract class LoggerService {
abstract log(message: string): void;
abstract error(message: string): void;
abstract warn(message: string): void;
}
class ConsoleLogger extends LoggerService {
log(message: string): void {
console.log(`[LOG] ${message}`);
}
error(message: string): void {
console.error(`[ERROR] ${message}`);
}
warn(message: string): void {
console.warn(`[WARN] ${message}`);
}
}
class App {
constructor(private logger: LoggerService) {}
run() {
this.logger.log("Application started");
this.logger.warn("This is a warning");
this.logger.error("This is an error");
}
}
const app = new App(new ConsoleLogger());
app.run();
抽象类与访问修饰符
抽象类中的成员可以有不同的访问级别,控制派生类和外部代码的访问权限。
abstract class AccessExample {
public abstract publicMethod(): void;
protected abstract protectedMethod(): void;
private privateMethod(): void {
console.log("This is private");
}
// 抽象私有方法在TypeScript 4.3+支持
// private abstract privateAbstractMethod(): void;
}
class AccessImpl extends AccessExample {
public publicMethod(): void {
console.log("Public method implementation");
}
protected protectedMethod(): void {
console.log("Protected method implementation");
// this.privateMethod(); // 错误:无法访问私有方法
}
// 不能实现父类的私有抽象方法
// private privateAbstractMethod(): void {}
}
const instance = new AccessImpl();
instance.publicMethod();
// instance.protectedMethod(); // 错误:受保护方法只能在类或其子类中访问
抽象类与静态成员
抽象类可以包含静态成员,这些成员属于类本身而不是实例。
abstract class MathOperations {
static PI: number = 3.14159;
static calculateCircleArea(radius: number): number {
return this.PI * radius * radius;
}
abstract calculate(): number;
}
class Square extends MathOperations {
constructor(private side: number) {
super();
}
calculate(): number {
return this.side * this.side;
}
}
console.log(MathOperations.calculateCircleArea(5)); // 78.53975
const square = new Square(4);
console.log(square.calculate()); // 16
抽象类与泛型
抽象类可以与泛型结合使用,创建更灵活的类型结构。
abstract class Repository<T> {
abstract getAll(): T[];
abstract getById(id: number): T | undefined;
abstract add(item: T): void;
abstract update(item: T): boolean;
abstract delete(id: number): boolean;
}
class UserRepository extends Repository<User> {
private users: User[] = [];
getAll(): User[] {
return [...this.users];
}
getById(id: number): User | undefined {
return this.users.find(u => u.id === id);
}
add(user: User): void {
this.users.push(user);
}
update(user: User): boolean {
const index = this.users.findIndex(u => u.id === user.id);
if (index >= 0) {
this.users[index] = user;
return true;
}
return false;
}
delete(id: number): boolean {
const initialLength = this.users.length;
this.users = this.users.filter(u => u.id !== id);
return this.users.length !== initialLength;
}
}
interface User {
id: number;
name: string;
email: string;
}
抽象类与装饰器
抽象类可以与装饰器一起使用,增强类的功能。
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
abstract class SealedAbstract {
abstract method(): void;
concreteMethod() {
console.log("Concrete implementation");
}
}
// 尝试修改SealedAbstract会失败
// SealedAbstract.prototype.newMethod = function() {}; // 错误:无法添加属性
抽象类与条件类型
在高级类型场景中,抽象类可以与条件类型结合使用。
abstract class ShapeBase {
abstract area(): number;
}
class Circle extends ShapeBase {
constructor(private radius: number) { super(); }
area(): number { return Math.PI * this.radius ** 2; }
}
class Square extends ShapeBase {
constructor(private side: number) { super(); }
area(): number { return this.side ** 2; }
}
type ShapeType<T extends ShapeBase> = T extends Circle ? "circle" : "square";
function getShapeType<T extends ShapeBase>(shape: T): ShapeType<T> {
return shape instanceof Circle ? "circle" : "square" as ShapeType<T>;
}
const circle = new Circle(5);
const square = new Square(4);
console.log(getShapeType(circle)); // "circle"
console.log(getShapeType(square)); // "square"
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn