散修带你入门鸿蒙应用开发基础第十三节:方法重写与抽象类应用
第十三节:方法重写与抽象类应用
炼气十三重天
【学习目标】
- 掌握
override关键字的显式重写语法,规范子类方法重写行为,提升代码可读性与可维护性; - 理解抽象类与抽象方法的核心意义,掌握
abstract关键字的使用规则; - 实现基于抽象类的商品规范约束,强制子类实现核心业务逻辑,规避“空实现”导致的业务异常;
- 结合鸿蒙电商场景,完成多态进阶实战,实现更严格的商品类型统一管理;
- 区分抽象类与普通类的适用场景,理解抽象类在大型鸿蒙工程中的架构价值。
【学习重点】
override显式重写的语法规范与工程意义;- 抽象类/抽象方法的定义规则(
abstract关键字、无方法体、子类强制实现); - 抽象类作为“规范父类”在鸿蒙电商商品管理中的落地;
- 抽象类与多态结合的进阶用法,实现子类逻辑的强制统一;
- 抽象类与普通类、接口的核心区别。
一、工程结构
复制第十二节的ClassObjectDemo_1工程,重命名为ClassObjectDemo_2,新增抽象商品类及秒杀商品子类,核心目录如下:
ClassObjectDemo_2/
├── entry/ # 应用主模块
│ ├── src/main/ets/
│ │ ├── pages/
│ │ │ └── Index.ets # 测试页面(抽象类+多态调用)
│ │ └── model/
│ │ │ ├── AbstractGoods.ets # 抽象父类:商品规范类(核心)
│ │ │ ├── PhysicalGoods.ets # 子类:实体商品(实现抽象方法)
│ │ │ ├── VirtualGoods.ets # 子类:虚拟商品(实现抽象方法)
│ │ │ └── SeckillGoods.ets # 新增子类:秒杀商品(扩展抽象类)
│ ├── resources/ # 资源目录(复用)
│ └── module.json5 # 模块配置(复用)
└── hvigorfile.ts # 构建脚本(复用)
二、方法重写规范:override关键字
2.1 隐式重写的问题
第十二节中子类重写父类方法时,仅通过“方法名、参数、返回值一致”实现隐式重写,存在以下核心隐患:
- 可读性差:外部开发者无法快速识别重写方法,需逐行追溯父类代码确认;
- 维护性低:父类方法签名变更(如参数/返回值修改)时,子类隐式重写方法会“失效”且无编译提示;
- 协作混乱:多人开发时,无法区分“子类新增方法”和“重写父类方法”,易引发逻辑冲突。
隐式重写的隐患示例
// 父类Goods 示例演示
export class Goods {
public profitRate: number = 0.1; // 默认10%利润率
protected _basePrice: number;
constructor(name: string, basePrice: number) {
this._basePrice = basePrice;
}
calculateSellingPrice(): number {
return this._basePrice * (1 + this.profitRate);
}
}
// 子类VirtualGoods(隐式重写)
export class VirtualGoods extends Goods {
// 无标识,无法直接判断是重写还是新增方法
calculateSellingPrice(): number {
this.profitRate = 0.15;
return this._basePrice * (1 + this.profitRate);
}
// 若父类后续将方法名改为calculatePrice,此处会变成子类新增方法,逻辑异常
}
2.2 override显式重写语法
ArkTS提供override关键字标记子类的重写方法,核心规则如下:
- 子类重写父类
public/protected方法时,建议显式添加override,明确标注重写关系; - 若
override方法未匹配父类方法签名(方法名/参数/返回值不一致),编译器直接报错,强制保证重写正确性; override不能用于重写父类private方法(子类无法访问private方法,无重写基础)。
结合十二节
protected修饰符的使用,override重写的方法仅能基于父类public/protected方法实现,无法重写private方法,这是继承场景下“访问控制+方法重写”的双重规范。
显式重写实战(改造虚拟商品类)
// model/VirtualGoods.ets(基于第十二节代码改造,后续会整合到抽象类体系中)
import { Goods } from './Goods';
export class VirtualGoods extends Goods {
// 虚拟商品专属属性:有效期(天)
public validDays: number;
// 虚拟商品专属属性:是否自动续费
public isAutoRenew: boolean;
/**
* 构造函数:初始化虚拟商品属性
* @param name 商品名称
* @param basePrice 商品底价
* @param validDays 有效期(默认30天)
* @param isAutoRenew 是否自动续费
* @param category 商品分类(可选)
*/
constructor(
name: string,
basePrice: number,
validDays: number,
isAutoRenew?: boolean,
category?: string,
profitRate: number = 0.15 // 虚拟商品默认15%利润率 (有默认值默认放在最后)
) {
super(name, basePrice);
this.profitRate = profitRate;
this.validDays = validDays < 1 ? 30 : validDays;
this.isAutoRenew = isAutoRenew ?? false;
}
// 显式标记重写父类方法,编译器校验签名一致性
override calculateSellingPrice(): number {
return Number((this._basePrice * (1 + this.profitRate)).toFixed(2));
}
// 显式标记重写父类打印方法
override printBaseInfo(): void {
super.printBaseInfo(); // 调用父类方法使用`super`
console.log(`
有效期:${this.validDays}天
自动续费:${this.isAutoRenew ? "开启" : "关闭"}
利润率:${this.profitRate * 100}%
`);
}
// 个性方法:延长有效期
extendValidity(days: number): void {
if (days <= 0) {
console.log("有效期延长失败:天数不合法");
return;
}
this.validDays += days;
console.log(`有效期延长${days}天,总计${this.validDays}天`);
}
}
2.3 override核心价值对比
| 特性 | 隐式重写 | 显式重写(override) |
|---|---|---|
| 代码可读性 | 需追溯父类确认重写关系 | 见名知意,直接标记重写方法 |
| 编译校验 | 无校验,父类方法变更易失效 | 强制校验方法签名,保证重写有效性 |
| 工程规范性 | 无统一标准,协作易混乱 | 符合鸿蒙工程编码规范,便于维护 |
| 调试效率 | 需对比父子类代码定位问题 | 快速定位重写方法,调试更高效 |
三、抽象类与抽象方法:强制子类实现核心逻辑
3.1 为什么需要抽象类?
第十二节的Goods普通类提供了calculateSellingPrice默认实现,但电商业务中:
- 实体商品、虚拟商品、秒杀商品的定价规则存在明显差异;
- 若子类未重写
calculateSellingPrice,会直接复用父类默认逻辑,导致不同商品的定价规则错误; - 无法强制要求子类实现个性化的核心方法,存在“空实现”“默认实现”的致命隐患。
抽象类核心价值:定义子类必须遵循的“规范接口”,强制子类实现核心业务方法,同时封装通用逻辑实现复用,兼顾“规范约束”与“代码复用”。
3.2 抽象类核心规则
- 抽象类定义:用
abstract关键字修饰类,抽象类不能直接实例化,仅能作为父类被继承; - 抽象方法定义:抽象类中用
abstract修饰的方法无方法体,仅定义方法签名(方法名+参数+返回值); - 子类强制实现:继承抽象类的子类必须实现父类所有抽象方法,否则编译报错;
- 混合成员:抽象类可同时包含抽象方法(强制子类实现)和普通方法/属性(提供通用逻辑复用)。
3.3 实战:定义抽象商品类
将通用商品类Goods改造为抽象类AbstractGoods,强制子类实现售价计算和库存校验的核心业务逻辑:
// model/AbstractGoods.ets(抽象父类:商品规范类)
export abstract class AbstractGoods {
public name: string;
public category: string = "商品分类";
protected _basePrice: number; // 改为protected,子类可访问
public profitRate: number; // 利润率(默认10%,子类可继承/修改)
constructor(
name: string,
basePrice: number,
category?: string,
profitRate: number = 0.1 // 默认10%利润率,与前节保持一致
) {
this.name = name;
this._basePrice = basePrice > 0 ? basePrice : 0; // 底价非负校验
this.profitRate = profitRate > 0 ? profitRate : 0.1; // 利润率非负校验,默认10%
this.category = category?.trim() || this.category;
}
// getter:受控读取底价
get basePrice() {
return this._basePrice;
}
// setter:受控修改底价
set basePrice(newPrice: number) {
if (newPrice < 0) {
console.log("商品底价不能为负");
return;
}
this._basePrice = newPrice;
}
// 共性方法:打印基础信息
printBaseInfo(): void {
console.log(`
商品名称:${this.name}
商品分类:${this.category}
商品底价:${this._basePrice}元
利润率:${this.profitRate * 100}%
`);
}
// 抽象方法1:强制子类实现售价计算
// 抽象方法默认public,不可用private修饰(子类无法实现)
abstract calculateSellingPrice(): number;
// 抽象方法2:强制子类实现库存校验(实体/虚拟/秒杀商品校验逻辑差异大)
abstract checkStock(amount: number): boolean;
}
3.4 子类实现抽象方法(强制约束)
1. 改造实体商品类(实现抽象方法,优化参数顺序)
// model/PhysicalGoods.ets
import { AbstractGoods } from './AbstractGoods';
export class PhysicalGoods extends AbstractGoods {
public stock: number; // 个性属性:实体库存
public weight: number; // 个性属性:商品重量(kg)
/**
* 构造函数:优化参数顺序(必选参数 → 有默认值参数,按常用度排序)
* @param name 商品名称
* @param basePrice 商品底价
* @param stock 库存数量
* @param weight 商品重量
* @param category 商品分类(默认:实体商品)
* @param profitRate 利润率(默认:0.1)
*/
constructor(
name: string,
basePrice: number,
stock: number,
weight: number,
category: string = "实体商品", // 有默认值:常用可选参数在前
profitRate: number = 0.1 // 有默认值:不常用可选参数在后
) {
super(name, basePrice, category, profitRate); // 调用抽象父类构造函数
this.stock = stock < 0 ? 0 : stock; // 库存非负校验
this.weight = weight < 0 ? 0 : weight; // 重量非负校验
}
// 必须实现抽象方法1:实体商品售价计算逻辑
override calculateSellingPrice(): number {
return parseFloat((this._basePrice * (1 + this.profitRate)).toFixed(2));
}
// 必须实现抽象方法2:实体商品库存校验
override checkStock(amount: number): boolean {
if (amount <= 0) {
console.log(`【${this.name}】校验失败:购买数量必须大于0`);
return false;
}
if (amount > this.stock) {
console.log(`【${this.name}】校验失败:库存不足,当前库存${this.stock}件,请求${amount}件`);
return false;
}
console.log(`【${this.name}】库存校验通过,剩余库存${this.stock}件`);
return true;
}
// 重写普通方法:扩展实体商品专属信息
override printBaseInfo(): void {
super.printBaseInfo(); // 复用父类通用打印逻辑
console.log(`
商品库存:${this.stock}件
商品重量:${this.weight}kg
`);
}
// 个性方法:基于库存校验的扣减逻辑
reduceStock(amount: number): void {
if (this.checkStock(amount)) {
this.stock -= amount;
console.log(`【${this.name}】库存扣减成功,剩余库存:${this.stock}件`);
}
}
}
2. 改造虚拟商品类(实现抽象方法)
// model/VirtualGoods.ets
import { AbstractGoods } from './AbstractGoods';
export class VirtualGoods extends AbstractGoods {
public validDays: number; // 有效期(天)
public isAutoRenew: boolean = false; // 自动续费(默认关闭)
/**
* 构造函数:优化参数顺序(必选参数 → 有默认值参数)
* @param name 商品名称
* @param basePrice 商品底价
* @param validDays 有效期(默认:30天)
* @param isAutoRenew 是否自动续费(默认:false)
* @param category 商品分类(默认:虚拟服务)
* @param profitRate 利润率(默认:0.15)
*/
constructor(
name: string,
basePrice: number,
validDays: number = 30, // 有默认值:常用可选参数在前
isAutoRenew: boolean = false, // 有默认值:代替可选参数?,避免undefined
category: string = "虚拟服务", // 有默认值
profitRate: number = 0.15 // 有默认值:不常用可选参数在后
) {
super(name, basePrice, category, profitRate); // 调用父类构造
this.validDays = validDays < 1 ? 30 : validDays; // 有效期校验
this.isAutoRenew = isAutoRenew;
}
// 重写普通方法:扩展打印逻辑(补充override,符合显式重写规范)
override printBaseInfo(): void {
super.printBaseInfo(); // 复用父类逻辑
console.log(`
有效期:${this.validDays}天
自动续费:${this.isAutoRenew ? "开启" : "关闭"}
`);
}
// 必须实现抽象方法1:虚拟商品售价计算逻辑
override calculateSellingPrice(): number {
const profitPart = this._basePrice * this.profitRate;
const serviceFee = this._basePrice * 0.05; // 5%服务费(虚拟商品专属)
const finalPrice = this._basePrice + profitPart + serviceFee;
return Number(finalPrice.toFixed(2)); // 统一数值类型处理
}
// 必须实现抽象方法2:虚拟商品无实体库存,仅校验购买数量
override checkStock(amount: number): boolean {
if (amount <= 0) {
console.log(`【${this.name}】校验失败:购买数量必须大于0`);
return false;
}
console.log(`【${this.name}】虚拟商品无实体库存,库存校验通过`);
return true;
}
// 个性方法:延长有效期
extendValidity(days: number): void {
if (days <= 0) {
console.log("有效期延长失败:天数不合法");
return;
}
this.validDays += days;
console.log(`有效期延长${days}天,总计${this.validDays}天`);
}
}
3. 新增秒杀商品类(扩展抽象类)
// model/SeckillGoods.ets(新增子类)
import { AbstractGoods } from './AbstractGoods';
export class SeckillGoods extends AbstractGoods {
public seckillStock: number; // 个性属性:秒杀库存
public discountRate: number; // 个性属性:折扣率(0.8=8折)
public seckillStartTime: Date; // 个性属性:秒杀开始时间(Date类型)
public seckillEndTime: Date; // 个性属性:秒杀结束时间(Date类型)
/**
* 构造函数:优化参数顺序,时间类型改为Date
* @param name 商品名称
* @param basePrice 商品底价
* @param seckillStock 秒杀库存
* @param discountRate 折扣率
* @param seckillStartTime 秒杀开始时间
* @param seckillEndTime 秒杀结束时间
* @param category 商品分类(默认:秒杀商品)
* @param profitRate 利润率(默认:0.1)
*/
constructor(
name: string,
basePrice: number,
seckillStock: number,
discountRate: number,
seckillStartTime: Date,
seckillEndTime: Date,
category: string = "秒杀商品", // 有默认值
profitRate: number = 0.1 // 有默认值
) {
super(name, basePrice, category, profitRate); // 分类默认值
this.seckillStock = seckillStock < 0 ? 0 : seckillStock; // 秒杀库存非负
// 折扣率约束:0.1~1(最低1折,最高原价)
this.discountRate = discountRate < 0.1 || discountRate > 1 ? 0.8 : discountRate;
this.seckillStartTime = seckillStartTime;
this.seckillEndTime = seckillEndTime;
}
// 必须实现抽象方法1:秒杀商品售价计算逻辑
override calculateSellingPrice(): number {
const now = new Date();
// 非秒杀时段按原价出售(Date对象直接比较,简化逻辑)
if (now < this.seckillStartTime || now > this.seckillEndTime) {
console.log(`【${this.name}】非秒杀时段(${this.seckillStartTime.toLocaleString()} - ${this.seckillEndTime.toLocaleString()}),按原价出售`);
const normalPrice = this._basePrice * (1 + this.profitRate);
return Number(normalPrice.toFixed(2));
}
// 秒杀时段按折扣价出售
const seckillPrice = this._basePrice * this.discountRate;
return Number(seckillPrice.toFixed(2));
}
// 必须实现抽象方法2:秒杀商品库存+时段双重校验
override checkStock(amount: number): boolean {
const now = new Date();
// 时段校验(Date对象直接比较)
if (now < this.seckillStartTime) {
console.log(`【${this.name}】校验失败:秒杀活动尚未开始(开始时间:${this.seckillStartTime.toLocaleString()})`);
return false;
}
if (now > this.seckillEndTime) {
console.log(`【${this.name}】校验失败:秒杀活动已结束(结束时间:${this.seckillEndTime.toLocaleString()})`);
return false;
}
// 数量校验
if (amount <= 0) {
console.log(`【${this.name}】校验失败:购买数量必须大于0`);
return false;
}
// 库存校验
if (amount > this.seckillStock) {
console.log(`【${this.name}】校验失败:秒杀库存不足,当前库存${this.seckillStock}件,请求${amount}件`);
return false;
}
console.log(`【${this.name}】秒杀库存校验通过,剩余库存${this.seckillStock}件`);
return true;
}
// 重写普通方法:扩展秒杀商品专属信息
override printBaseInfo(): void {
super.printBaseInfo(); // 复用父类逻辑
const startTime = this.seckillStartTime.toLocaleString();
const endTime = this.seckillEndTime.toLocaleString();
console.log(`
秒杀库存:${this.seckillStock}件
秒杀折扣:${(this.discountRate * 10).toFixed(1)}折
秒杀时段:${startTime} - ${endTime}
`);
}
// 个性方法:秒杀库存扣减
// 下节接口章节将把“秒杀能力”抽离为独立接口(ISeckill),通过implements实现多维度能力扩展
reduceSeckillStock(amount: number): void {
if (this.checkStock(amount)) {
this.seckillStock -= amount;
console.log(`【${this.name}】秒杀库存扣减${amount}件,剩余:${this.seckillStock}件`);
}
}
}
四、抽象类+多态:实现商品统一管控
4.1 核心调用逻辑(规范+灵活)
通过抽象类类型数组统一管理所有商品子类实例,实现“规范接口+个性化实现”的统一调用。UI代码见附录,核心逻辑如下:
import { PhysicalGoods } from '../model/PhysicalGoods';
import { VirtualGoods } from '../model/VirtualGoods';
import { SeckillGoods } from '../model/SeckillGoods';
import { AbstractGoods } from '../model/AbstractGoods';
import { LengthMetrics } from '@kit.ArkUI';
@Entry
@Component
struct Index {
@State goodsList: AbstractGoods[] = [
new PhysicalGoods("鸿蒙Mate70手机", 6999, 200, 0.2, "智能手机"),
new VirtualGoods("鸿蒙VIP会员", 99, 365, true),
new SeckillGoods("鸿蒙智能手表GT5(秒杀款)", 1299, 50, 0.7, new Date(), new Date(Date.now() + 3600 * 1000 * 2))];
/**
* 统一执行商品核心逻辑
*/
private callSubclassMethods(): void {
console.log("===== 鸿蒙电商商品核心逻辑执行 =====");
this.goodsList.forEach((goods, index) => {
console.log(`\n【商品${index + 1}:${goods.name}】`);
goods.printBaseInfo(); // 复用/扩展父类打印逻辑
console.log(`最终售价:${goods.calculateSellingPrice()}元`); // 执行子类售价计算
// 库存校验(执行子类校验逻辑)
const checkResult = goods.checkStock(2);
console.log(`购买2件库存校验结果:${checkResult ? "✅ 通过" : "❌ 失败"}`);
// 调用子类专属方法(instanceof 判断)
if (goods instanceof PhysicalGoods) {
goods.reduceStock(2);
} else if (goods instanceof SeckillGoods) {
goods.reduceSeckillStock(2);
}
});
// 触发UI刷新:扩展运算符创建新数组,改变引用
this.goodsList = [...this.goodsList];
}
/**
* 扣减实体商品库存(直接断言+提示)
*/
private handleReduceStock(goods: AbstractGoods, amount: number = 1): void {
if (goods instanceof PhysicalGoods) {
console.log(`\n===== 执行${goods.name}:扣减库存${amount}件 =====`);
goods.reduceStock(amount);
this.goodsList = [...this.goodsList]; // 触发UI刷新
} else {
console.log(`\n❌ ${goods.name}不是实体商品,无法扣减库存`);
}
}
/**
* 扣减秒杀商品库存(直接断言+提示)
*/
private handleReduceSeckillStock(goods: AbstractGoods, amount: number = 1): void {
if (goods instanceof SeckillGoods) {
console.log(`\n===== 执行${goods.name}:扣减秒杀库存${amount}件 =====`);
goods.reduceSeckillStock(amount);
this.goodsList = [...this.goodsList]; // 触发UI刷新
} else {
console.log(`\n❌ ${goods.name}不是秒杀商品,无法扣减秒杀库存`);
}
}
/**
* 购买虚拟商品(直接断言+提示)
*/
private handleBuyVirtualGoods(goods: AbstractGoods): void {
if (goods instanceof VirtualGoods) {
console.log(`\n===== 执行${goods.name}:购买操作 =====`);
console.log(`${goods.name}购买成功!有效期:${goods.validDays}天 | 自动续费:${goods.isAutoRenew ? '开启' : '关闭'}`);
} else {
console.log(`\n❌ ${goods.name}不是虚拟商品,无法执行购买操作`);
}
}
/**
* 格式化日期为友好的字符串
*/
private formatDate(date: Date): string {
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
build() {
Column() {
// 页面标题
Text("抽象类+多态 商品管理实战")
.fontSize(22)
.fontWeight(FontWeight.Bold)
.margin(20);
// 全局操作按钮:执行所有商品的核心逻辑
Button("执行所有商品核心操作")
.width('90%')
.height(40)
.backgroundColor(Color.Blue)
.fontColor(Color.White)
.borderRadius(8)
.margin({ bottom: 10 })
.onClick(() => this.callSubclassMethods());
// 商品列表滚动区域
Scroll() {
Column() {
// 统一渲染所有商品(多态渲染)
ForEach(this.goodsList, (goods: AbstractGoods) => {
Column() {
// 商品基础信息
Text(goods.name)
.fontSize(18)
.fontWeight(FontWeight.Medium);
Text(`分类:${goods.category}`)
.fontSize(14)
.margin(2)
.fontColor('#666666');
Text(`底价:¥${goods.basePrice} | 利润率:${(goods.profitRate * 100).toFixed(1)}%`)
.fontSize(14)
.margin(2)
.fontColor('#666666');
Text(`售价:¥${goods.calculateSellingPrice().toFixed(2)}`)
.fontSize(16)
.fontColor(Color.Red)
.margin(5);
// 渲染子类专属信息
if (goods instanceof PhysicalGoods) {
Text(`库存:${goods.stock}件 | 重量:${goods.weight.toFixed(2)}kg`)
.fontSize(12)
.margin(2)
.fontColor('#999999');
} else if (goods instanceof VirtualGoods) {
Text(`有效期:${goods.validDays}天 | 自动续费:${goods.isAutoRenew ? '开启' : '关闭'}`)
.fontSize(12)
.margin(2)
.fontColor('#999999');
} else if (goods instanceof SeckillGoods) {
Text(`秒杀折扣:${(goods.discountRate * 10).toFixed(1)}折 | 剩余库存:${goods.seckillStock}件`)
.fontSize(12)
.margin(2)
.fontColor('#999999');
Text(`秒杀时间:${this.formatDate(goods.seckillStartTime)} - ${this.formatDate(goods.seckillEndTime)}`)
.fontSize(10)
.margin(2)
.fontColor('#ff6600');
}
Flex({ space:{main:LengthMetrics.px(10),cross:LengthMetrics.px(10)}, justifyContent: FlexAlign.Center, wrap: FlexWrap.Wrap }) {
// 实体商品:扣减库存按钮
if (goods instanceof PhysicalGoods) {
Button("扣减库存")
.fontSize(10)
.padding({ left: 12, right: 12, top: 5, bottom: 5 })
.backgroundColor(Color.Green)
.fontColor(Color.White)
.borderRadius(4)
.onClick(() => this.handleReduceStock(goods, 1));
}
// 秒杀商品:扣减秒杀库存按钮
if (goods instanceof SeckillGoods) {
Button("扣减秒杀库存")
.fontSize(10)
.padding({ left: 12, right: 12, top: 5, bottom: 5 })
.backgroundColor(Color.Orange)
.fontColor(Color.White)
.borderRadius(4)
.onClick(() => this.handleReduceSeckillStock(goods, 1));
}
// 虚拟商品:购买VIP按钮
if (goods instanceof VirtualGoods) {
Button("购买Vip")
.fontSize(10)
.padding({ left: 12, right: 12, top: 5, bottom: 5 })
.backgroundColor(Color.Pink)
.fontColor(Color.White)
.borderRadius(4)
.onClick(() => this.handleBuyVirtualGoods(goods));
}
}.margin({ top: 10 })
}
.width('90%')
.padding(15)
.backgroundColor(Color.White)
.borderRadius(10)
.shadow({ radius: 5, color: '#cccccc', offsetX: 2, offsetY: 2 })
.margin(10);
})
}.width('100%')
}.layoutWeight(1)
.width('100%')
}
.width('100%')
.height('100%')
.backgroundColor('#f5f5f5')
.padding(10);
}
}
4.2 运行预览


五、抽象类与普通类的核心区别
| 特性 | 抽象类(abstract class) | 普通类(class) |
|---|---|---|
| 实例化 | 不可直接实例化,仅能被继承 | 可直接实例化 |
| 成员组成 | 抽象方法+普通方法/属性 | 仅普通方法/属性 |
| 子类约束 | 强制子类实现所有抽象方法 | 子类可选择是否重写父类方法 |
| 核心价值 | 定义规范、强制约束、统一接口 | 封装逻辑、实现复用、实例化调用 |
| 编译校验 | 子类未实现抽象方法直接报错 | 无强制校验 |
| 适用场景 | 大型工程的基础规范类(商品基类) | 具体业务对象(工具类、单一实例) |
六、常见问题解答
6.1 抽象类可以有构造函数吗?
可以。抽象类的构造函数用于初始化自身属性,供子类通过super()调用——虽然抽象类不能直接实例化,但构造函数是父子类属性传递的核心通道,是抽象类封装通用属性的必要手段。
6.2 抽象类可以继承普通类吗?
可以。抽象类可通过extends继承普通类,同时可在抽象类中新增抽象方法,强制子类实现更多规范(如:abstract class AbstractGoods extends BaseData {})。
6.3 抽象方法可以有访问修饰符吗?
可以。抽象方法可添加public/protected修饰符(默认public),但不能使用private——子类无法访问父类private方法,自然无法实现抽象方法,编译器会直接报错。
6.4 抽象类和接口的核心区别是什么?
- 抽象类是“部分实现”:包含通用逻辑+规范约束(抽象方法),侧重“是不是”(如:实体商品“是”商品);
- 接口是“完全规范”:仅定义方法签名/属性约束,无任何实现逻辑,侧重“有没有”(如:商品“有”退换能力、“有”秒杀能力);
- 语法限制:一个类只能继承一个抽象类,但可实现多个接口(后续接口章节会详细讲解)。
6.5 有默认值的参数和可选参数(?)该如何排序?
遵循必选参数 → 有默认值的参数 → 可选参数(?)的语法规则,且优先使用有默认值的参数代替可选参数。原因:
- 可选参数(?)放在有默认值的参数前会编译报错;
- 有默认值的参数可避免
undefined风险,语义更清晰(如isAutoRenew: boolean = false比isAutoRenew?: boolean更安全)。
七、课堂小结
override关键字实现方法显式重写,提升代码可读性,编译器强制校验方法签名一致性,是鸿蒙工程编码的规范要求;- 抽象类通过
abstract关键字定义,不可直接实例化,可包含抽象方法(无方法体)和普通方法/属性; - 子类继承抽象类时必须实现所有抽象方法,这是保证业务逻辑完整性的核心约束,杜绝“空实现”隐患;
- 抽象类+多态的组合,实现了“规范统一接口+子类个性化实现”,是鸿蒙电商商品管理的核心架构模式;
- 抽象类侧重“定义规范、强制约束”,普通类侧重“封装逻辑、实例化复用”,需根据业务场景合理选型;
- 参数声明遵循“必选 → 有默认值 → 可选(?)”顺序,优先用有默认值的参数代替可选参数,避免
undefined风险。
八、代码仓库
工程名称:ClassObjectDemo_2
本节代码已同步至:https://gitee.com/juhetianxia321/harmony-os-code-base.git
九、下节预告
ArkTS仅支持单继承,无法满足商品“同时具备秒杀、退换、预售”等多维度能力——下一节抽象与面向接口编程将突破单继承限制:
- 接口的定义语法与核心规则(
interface关键字、方法签名、属性约束); - 掌握
implements关键字,实现类对多接口的实现,为商品灵活叠加组合能力; - 深度辨析“抽象类(是不是)”与“接口(有没有)”的核心差异,明确技术选型逻辑;
- 基于“抽象类+接口”重构商品架构,打造“基础规范+灵活能力”的高内聚设计,适配复杂电商业务场景。
十、鸿蒙开发者学习与认证指引
(一)、官方学习班级报名(免费)
- 班级链接:HarmonyOS赋能资源丰富度建设(第四期)
- 学号填写规则:填写个人手机号码即可完成班级信息登记
(二)、HarmonyOS应用开发者认证考试(免费)
- 考试链接:HarmonyOS开发者能力认证入口
- 认证等级及适配人群
- 基础认证:适配软件工程师、移动应用开发人员,需掌握HarmonyOS基础概念、DevEco Studio基础使用、ArkTS及ArkUI基础开发等能力;
- 高级认证:适配项目经理、工程架构师,需掌握系统核心技术理念、应用架构设计、关键技术开发及应用上架运维等能力;
- 专家认证:适配研发经理、解决方案专家,需掌握分布式技术原理、端云一体化开发、跨端迁移及性能优化等高级能力。
- 认证权益:通过认证可获得电子版证书以及其他专属权益。
浙公网安备 33010602011771号