在 TypeScript 面向对象编程中,接口(Interface)和抽象类(Abstract Class)是实现代码抽象化与规范化的核心机制。二者分别承担“契约定义”与“模板实现”的角色,在不同场景下发挥着关键作用。
接口本质是一种“能力契约”,它仅规定类必须实现的方法和属性结构,自身不包含任何具体实现逻辑。这种机制确保了实现类严格遵循预设规范,为多态设计提供基础。
例如,定义一个表示“可飞行”能力的接口 Flyable:
interface Flyable { fly(height: number): void }
当 Bird 类需要具备飞行能力时,必须通过 implements 关键字实现该接口,并完整实现 fly 方法:
class Bird implements Flyable { fly(height: number): void { console.log(Flying at ${height}m); } }
接口的强制约束性:若实现类未完整实现接口方法(如参数类型不匹配、缺少方法),TypeScript 会在编译阶段抛出错误,确保契约被严格遵守。
抽象类是“包含未完成方法的模板”,它可同时包含需子类实现的抽象方法(用 abstract 修饰)和可直接复用的普通方法。这种特性使其成为代码复用与强制实现结合的理想载体。
定义交通工具抽象类 Vehicle:
abstract class Vehicle { abstract run(): void; // 抽象方法:需子类实现具体行驶逻辑 honk(): void { console.log('Honk!'); } // 普通方法:直接提供鸣笛功能 }
抽象类不能直接实例化,必须通过子类继承并实现所有抽象方法。例如 Car 类继承 Vehicle:
class Car extends Vehicle { run(): void { console.log('Car running on road'); } }
const car = new Car(); car.run(); // 输出:Car running on road car.honk(); // 输出:Honk!(直接复用抽象类方法)
接口与抽象类的差异主要体现在实现方式和继承机制上,具体对比如下:
接口 vs 抽象类关键差异
implements 实现多个接口(如 class A implements B, C),但只能通过 extends 继承一个抽象类(遵循单继承原则)。 接口适用场景:需规范多类行为、支持多实现时(如不同模块的通信协议);抽象类适用场景:需复用通用逻辑、强制子类实现核心方法时(如框架中的基础组件)。
在后端开发中,接口常用于定义跨模块的通信规范。例如数据库操作接口 DB 可统一不同数据库的查询方法:
interface DB { query(sql: string): any }
针对 MySQL 和 PostgreSQL 分别实现接口:
class MySQLDB implements DB { query(sql: string): any { return MySQL executed: ${sql}; } }
class PostgreSQLDB implements DB { query(sql: string): any { return PostgreSQL executed: ${sql}; } }
上层业务代码可直接依赖 DB 接口调用 query 方法,无需关心底层数据库类型,实现“面向接口编程”的解耦效果:
function executeQuery(db: DB, sql: string) { return db.query(sql); }
executeQuery(new MySQLDB(), "SELECT * FROM users"); // 输出:MySQL executed: SELECT * FROM users
需求:实现支持微信/支付宝支付的系统,需包含统一支付方法、通用日志记录,以及各支付方式的特有逻辑。
实现步骤:
定义支付接口 IPayment,规范核心支付方法:interface IPayment { pay(amount: number): boolean }
创建抽象类 BasePayment,实现通用日志记录逻辑:
`abstract class BasePayment implements IPayment {
abstract pay(amount: number): boolean; // 抽象支付方法
// 通用日志逻辑:所有支付方式共享
protected log(platform: string, amount: number, success: boolean): void {
console.log([${new Date().toISOString()}] ${platform} pay ${amount} CNY: ${success ? 'success' : 'fail'});
}
}`
实现具体支付方式:class WechatPayment extends BasePayment { pay(amount: number): boolean { const success = amount > 0; // 模拟支付校验 this.log('WeChat', amount, success); return success; } }
class AlipayPayment extends BasePayment { pay(amount: number): boolean { const success = amount > 0; this.log('Alipay', amount, success); return success; } }
使用示例:
`const wechat = new WechatPayment();
wechat.pay(200); // 输出日志并返回 true
const alipay = new AlipayPayment();
alipay.pay(-50); // 输出日志并返回 false`
通过接口定义统一支付标准,抽象类复用日志逻辑,子类聚焦具体支付实现,该设计既保证了规范一致性,又最大化减少了代码冗余。
接口与抽象类均为 TypeScript 抽象化工具,但定位不同:接口专注于“规范定义”,支持多实现;抽象类专注于“模板复用”,支持单继承。在实际开发中,二者常结合使用——接口定义核心方法契约,抽象类实现通用逻辑,子类提供具体业务实现,共同构建灵活且可维护的代码架构。