什么时候该用类继承?
在写程序的时候,经常会遇到这样的情况:好几个功能很像,但又不完全一样。比如做一款电商系统,商品有普通商品、秒杀商品、会员专属商品。它们都有名称、价格、库存这些基本属性,但在打折方式、购买权限上又有区别。
这时候如果每个商品类型都从头写一遍,重复代码会很多。一个改了,其他几个也得跟着改,维护起来头疼。类继承就是为了解决这种问题而生的。
基础结构复用
假设我们先定义一个基础的商品类,把共有的字段和方法放进去:
class Product {
constructor(name, price, stock) {
this.name = name;
this.price = price;
this.stock = stock;
}
display() {
console.log(`{this.name} 价格:{this.price} 元,库存:{this.stock}件`);
}
}接下来,会员商品只需要在原有基础上扩展购买逻辑:
class MemberProduct extends Product {
constructor(name, price, stock, discount) {
super(name, price, stock);
this.discount = discount;
}
buy(memberLevel) {
if (memberLevel >= 3) {
const finalPrice = this.price * this.discount;
console.log(`会员以 {finalPrice} 元购买了 {this.name}`);
} else {
console.log(`等级不够,无法购买`);
}
}
}这样既保留了原始功能,又增加了专属逻辑,代码清晰还容易扩展。
统一接口,差异化实现
另一个常见场景是处理不同类型的支付方式。微信支付、支付宝、银行卡支付,流程大体相似:验证、扣款、返回结果。但每个环节的具体实现不一样。
通过继承,可以定义一个抽象的支付类作为模板:
class Payment {
process(amount) {
this.validate();
this.deduct(amount);
return this.confirm();
}
validate() { throw new Error('子类必须实现 validate'); }
deduct() { throw new Error('子类必须实现 deduct'); }
confirm() { throw new Error('子类必须实现 confirm'); }
}然后各个具体支付方式继承它,各自实现细节:
class WeChatPay extends Payment {
validate() { console.log('验证微信账户状态'); }
deduct(amount) { console.log(`微信扣除 {amount} 元`); }
confirm() { return '微信支付成功'; }
}调用时不管用哪种支付,都用同一个 process 方法,系统更稳定,新增支付方式也不用改主流程。
模拟现实中的层级关系
再比如开发一个宠物管理系统,猫和狗都是动物,都有名字、年龄、吃东西的行为。但猫会喵喵叫,狗会汪汪叫。
建一个 Animal 基类,封装通用行为,再分别派生 Cat 和 Dog 类,重写叫声方法。这样结构清楚,读代码的人一看就明白它们之间的关系。
类继承不是万能钥匙,但如果用对了地方,能让代码少点“复制粘贴”,多点条理。尤其是在业务不断变化的项目里,改一处不用动八处,省下的时间够喝两杯咖啡了。