零基础鸿蒙应用开发第二十一节:面向对象思想入门与类的定义

零基础鸿蒙应用开发学习计划表

【学习目标】

  1. 理解“类(模板)-对象(实例)”的核心关系,区分面向过程与面向对象编程思维在鸿蒙开发中的适配场景;
  2. 掌握ArkTS类的标准定义语法(属性声明、构造函数、实例方法),熟练使用new关键字实例化对象;
  3. 吃透this关键字的含义与使用场景,规避鸿蒙开发中this的常见使用错误;
  4. 理解封装的核心意义,掌握public/private访问修饰符(protected将在下一节继承章节讲解),实现数据的安全封装;
  5. 掌握getter/setter方法的设计思路,理解其与普通方法的本质区别,实现鸿蒙应用中商品售价、库存、折扣属性的安全读写。

【学习重点】

  • ArkTS类“先声明、后赋值”的核心规则,区分与TypeScript的核心差异;
  • this关键字在构造函数/实例方法中的正确使用,规避“属性未绑定”错误;
  • private修饰符在鸿蒙电商场景(商品售价、折扣)的核心应用;
  • getter/setter方法与普通方法的本质区别,掌握set/get关键字的设计初衷与选型原则;
  • 类内部方法与全局函数的语法差异(function关键字的使用规则);
  • 面向对象封装思想在鸿蒙业务模型类(商品)中的落地。

一、工程结构

本节我们将创建名为ClassObjectDemo的工程,基于 鸿蒙5.0(API12) 开发,使用 DevEco Studio 6.0+ 工具,项目结构目录如下:

ClassObjectDemo/
├── entry/                          # 应用主模块
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/                # ArkTS代码根目录
│   │   │   │   ├── pages/          # 页面代码目录
│   │   │   │   │   └── Index.ets   # 测试页面
│   │   │   │   └── model/          # 业务模型类目录
│   │   │   │       └── Goods.ets   # 商品类(核心)
│   │   │   ├── resources/          # 资源目录(非本节重点)
│   │   │   └── module.json5        # 模块配置文件
│   │   └── oh-package.json5        # 工程依赖配置
└── hvigorfile.ts                   # 构建脚本(默认生成)

二、类与对象基础解析

2.1 面向过程 vs 面向对象

编程的核心是“处理数据+实现逻辑”,两种思维在鸿蒙电商开发中的适配性差异显著:

编程思维 核心特点 鸿蒙适配场景 缺点
面向过程 数据与方法分离,按步骤执行 简单逻辑(如单个商品信息打印) 多实例场景代码冗余、维护性差
面向对象 数据与方法封装为类,实例化调用 多实例管理(电商商品列表) 入门稍复杂,适配工程化开发

2.2 面向过程实现

// 定义电商商品数据(仅保留核心字段:名称、售价、折扣、库存)
let productName: string = "鸿蒙Mate70手机";
let productPrice: number = 5999;
let productDiscount: number = 0.8; // 8折(注:0.8表示8折,非0.8折)
let productStock: number = 100;

// 封装打印方法(需手动传参)
function printGoodsInfo(name: string, price: number, discount: number, stock: number): void {
  const finalPrice = price * discount; // 折扣后价格
  console.log(`商品名称:${name},原价:${price}元,折扣:${discount * 10}折,折后价:${finalPrice}元,库存:${stock}件`);
}

// 执行逻辑
printGoodsInfo(productName, productPrice, productDiscount, productStock);

打印输出

商品名称:鸿蒙Mate70手机,原价:5999元,折扣:8折,折后价:4799.2元,库存:100件

2.3 核心概念解析

在看面向对象的具体实现前,先明确三个核心概念,这是理解面向对象的基础:

  • 类(Class):描述一类事物的通用模板,定义了该类事物的共同属性和行为(比如电商场景中的Goods类,会定义商品的名称、售价、库存、折扣这些共同属性,以及打印信息、计算折后价这些共同行为);
  • 对象(Object):类的具体实例,是类模板的具象化(比如phoneGoods类的实例,对应“鸿蒙Mate70手机”这个具体商品,watch是另一个实例,对应“鸿蒙智能手表”);
  • 封装:将数据(属性)和操作数据的逻辑(方法)打包到类中,外部仅通过暴露的接口操作数据,无需关心内部实现(比如商品的售价是敏感数据,我们可以封装起来,外部只能通过指定方式修改,不能直接赋值)。

2.4 类的标准定义语法

ArkTS类遵循“先声明、后赋值”原则,不支持 TypeScript中“构造函数参数加public简化属性定义”的写法,标准模板:

export class 类名 {
  // 1. 公共属性声明:指定类型,可选默认值(非敏感数据,如商品名称、分类)
  公共属性名: 数据类型;
  带默认值属性名: 数据类型 = 默认值;

  // 2. 私有属性声明:敏感数据,仅类内访问(如商品售价、库存、折扣)
  private _私有属性名: 数据类型 = 默认值;

  // 3. 构造函数:实例化时初始化属性,需先声明后赋值,可选参数放置最后
  constructor(参数1: 数据类型, 参数2: 数据类型, 可选参数?: 数据类型) {
    this.公共属性名 = 参数1; // 给公共属性赋值
    this._私有属性名 = 参数2; // 给私有属性赋值
  }

  // 4. 实例方法:描述对象行为,禁止使用function关键字
  无返回值方法(): void {
    console.log(this.公共属性名); // 访问属性必须加this
  }

  有返回值方法(): 返回值类型 {
    return this._私有属性名 * this._私有属性名2; // 如售价×折扣计算折后价
  }
}

2.5 面向对象实现

有了核心概念和语法基础,我们就可以用面向对象的方式重构电商商品的逻辑,解决面向过程的冗余问题:

步骤1:定义商品类(数据+行为封装)

// model/Goods.ets 
export class Goods {
  // 公共属性:类内外均可访问,默认可省略public
  public name: string;
  // 默认分类名称,赋予默认值"商品分类"
  category: string = "商品分类";

  // 私有属性:仅类内可访问
  private _price: number; // 商品售价(核心案例:加下划线区分getter/setter)
  private stock: number; // 商品库存
  private discount: number = 1; // 商品折扣(默认1=原价/10折)

  // 构造函数:初始化属性(必须先声明后赋值)
  constructor(name: string, price: number, stock: number, discount?: number, category?: string) {
    this.name = name;
    // 基础校验:售价、库存不能为负,负数则设为0(使用Math.max简化逻辑)
    this._price = Math.max(price, 0);
    this.stock = Math.max(stock, 0);

    // 折扣校验:传入合法值则赋值,否则用默认值(1=原价/10折)
    if (discount && discount > 0 && discount <= 1) {
      this.discount = discount;
    }
    
    // 分类:传入合法值则覆盖默认值(空值/空格不覆盖)
    this.category = category?.trim() || this.category;
  }

  // 实例方法:打印商品信息(行为封装)
  printInfo(): void {
    const finalPrice = parseFloat((this._price * this.discount).toFixed(2)); // 保留两位小数
    console.log(`
      商品名称:${this.name}
      商品分类:${this.category}
      商品原价:${this._price}元
      商品折扣:${this.discount * 10}折
      折后售价:${finalPrice}元
      商品库存:${this.stock}件
    `);
  }
}

步骤2:调用商品类

// pages/Index.ets 导入Goods
import { Goods } from '../model/Goods';

aboutToAppear() {
  // 实例化商品对象(类→对象的过程)
  const phone = new Goods("鸿蒙Mate70手机", 5999, 100, 0.8, "数码产品");
  const watch = new Goods("鸿蒙智能手表", 1299, 50, 0.9, "穿戴设备");
  
  // 调用对象的方法
  phone.printInfo();
  watch.printInfo();
  
  // 访问公共属性(可直接读写)
  console.log(`分类名字:${phone.category}`); // 输出:数码产品
  phone.category = "新数码产品";
  console.log(`分类名字:${phone.category}`); // 输出:新数码产品
  
  // 私有属性无法直接访问(编译报错)
  // console.log("价格:",phone._price);
  // console.log("库存",phone.stock);
}

打印输出

// phone.printInfo() 输出:
      商品名称:鸿蒙Mate70手机
      商品分类:数码产品
      商品原价:5999元
      商品折扣:8折
      折后售价:4799.2元
      商品库存:100件

// watch.printInfo() 输出:
      商品名称:鸿蒙智能手表
      商品分类:穿戴设备
      商品原价:1299元
      商品折扣:9折
      折后售价:1169.1元
      商品库存:50件

// 访问公共属性输出:
分类名字:数码产品
分类名字:新数码产品

2.6 function关键字使用规则

核心规则(强制)

  1. 全局/独立函数:必须显式使用function关键字(或箭头函数)声明,这是ArkTS的基础语法规则;
  2. 类内部方法(实例方法、getter/setter、静态方法):禁止使用function关键字,直接以“方法名(参数): 返回值类型”的形式声明,加function会直接触发语法报错。
// 示例1:全局函数(必须加function)
function globalPrintName(name: string): void {
  console.log(`全局函数:${name}`);
}
// 调用全局函数
globalPrintName("鸿蒙Mate70手机");

// 示例2:类内部方法(无需加function)
class ErrorExample {
  name: string;
  constructor(name: string) {
    this.name = name;
  }

  // ✅ 正确:类内部方法无function关键字
  printName(): void {
    console.log(`类方法:${this.name}`);
  }

  // ❌ 错误:类内部方法加function关键字,语法报错
  // function printError(): void {
  //   console.log(this.name);
  // }
}
// 调用类方法
const errorObj = new ErrorExample("鸿蒙智能手表");
errorObj.printName();

打印输出

全局函数:鸿蒙Mate70手机
类方法:鸿蒙智能手表

2.7 this关键字深度解析

this指向“当前对象实例”,仅在构造函数和实例方法中有效,核心作用是区分“类的属性”和“方法/构造函数的参数”。例如:

  • 构造函数中的this._price:指类的私有属性_price
  • 构造函数的参数price:仅作用于构造函数内部,与类属性无关;
  • 若省略this(如console.log(price)),会被识别为局部变量(参数),而非类属性,导致逻辑错误。

2.8 常见错误及规避示例

// 错误示例对比
// ❌ ArkTS编译报错示例:未声明属性直接在构造函数赋值
class ErrorExample1 {
  constructor(name: string, price: number) {
    this.name = name; // 报错:Property 'name' does not exist on type 'ErrorExample1'
    this._price = price; // 报错:Property '_price' does not exist on type 'ErrorExample1'
  }
}

// ✅ 正确写法:先声明、后赋值
class ErrorExample2 {
  // 第一步:声明属性(公共+私有)
  name: string;
  private _price: number;

  constructor(name: string, price: number) {
    // 第二步:构造函数赋值(必须加this)
    this.name = name;
    this._price = Math.max(price, 0);

    // ❌ 错误:参数自赋值,类属性未初始化
    // name = name;
    // _price = price;

    // ❌ 错误:访问未定义的局部变量(混淆参数与类属性)
    // console.log(price); // 这里是构造函数参数,不是类属性
    // console.log(_price); // 未声明的局部变量(类属性需用this._price访问)
  }

  // 正确访问类属性
  getPrice(): number {
    return this._price; // 必须加this访问类属性
  }
}

// 调用正确示例
const correctObj = new ErrorExample2("鸿蒙平板", 2999);
console.log(`商品名称:${correctObj.name}`);
console.log(`商品售价:${correctObj.getPrice()}元`);

打印输出

商品名称:鸿蒙平板
商品售价:2999元

三、封装思想及访问控制应用

3.1 封装的核心意义

本节封装案例围绕鸿蒙电商核心的“商品类”展开,封装的核心目标是:将商品的核心数据(售价、库存、折扣)与操作逻辑(价格计算、信息打印)打包为独立的业务模型,外部仅通过暴露的接口(如getter/setter、普通方法)操作数据,既保证数据安全(如售价不能为负),又降低代码耦合度。

鸿蒙电商开发中需封装的场景:

  • 敏感数据(如售价、库存、折扣):需校验合法性,禁止外部随意修改;
  • 普通数据(如商品名称、分类):可直接暴露,无需额外限制。

3.2 访问修饰符规则

ArkTS提供三种核心访问修饰符,默认所有成员为public,用于控制属性/方法的访问范围:

修饰符 访问范围 鸿蒙电商应用场景 示例
public 类内、类外均可访问 普通非敏感数据(商品名称、分类) public name: string;
private 仅类内可访问 敏感数据(商品售价、库存、折扣) private _price: number;
protected 类内、子类可访问,类外不可 层级类中间数据(下一节继承章节讲解) protected config: string;

3.3 读写私有数据的两种方式

私有数据(如_pricestockdiscount)无法被外部直接访问,需通过“公共方法”或“getter/setter”实现受控读写。本节以_price(售价)为核心案例,演示两种方式的实现与区别。

1. 通过公共方法访问/修改私有字段(传统方式)

// model/Goods.ets 新增公共方法(可选,用于对比getter/setter)
export class Goods {
  // 其他代码不变...

  /**
   * 公共方法:设置售价(带校验)
   * @param newPrice 新售价
   */
  setPrice(newPrice: number) {
    if (newPrice < 0) {
      console.warn(`【${this.name}】售价不能为负,修改失败`);
      return;
    }
    this._price = newPrice;
    console.log(`【${this.name}】售价修改为:${newPrice}元`);
  }

  /**
   * 公共方法:获取售价
   * @returns 当前售价
   */
  getPrice() {
    return this._price;
  }
}

// pages/Index.ets 测试公共方法
aboutToAppear() {
  const phone = new Goods("鸿蒙Mate70手机", 5999, 100, 0.8, "数码产品");
  phone.setPrice(-100); // 非法值:修改失败
  console.log(`第一次读取售价:${phone.getPrice()}`); // 输出:5999
  phone.setPrice(6999); // 合法值:修改成功
  console.log(`第二次读取售价:${phone.getPrice()}`); // 输出:6999
}

打印输出

W 鸿蒙Mate70手机】售价不能为负,修改失败
第一次读取售价:5999
【鸿蒙Mate70手机】售价修改为:6999元
第二次读取售价:6999

上述普通方法可实现私有属性的受控读写,但ArkTS提供了更贴合“属性操作”语义的语法——getter/setter,下面我们用它重构商品类的私有属性访问逻辑。

2. 通过getter/setter访问/修改私有字段(推荐方式)

getter/setter是ArkTS专门为“属性受控读写”设计的语法,比普通方法更贴合“属性操作”的语义,本节重点讲解这种方式:

// model/Goods.ets 替换公共方法为getter/setter
export class Goods {
  // 公共属性(不变)
  public name: string;
  category: string = "商品分类";

  // 私有属性:仅类内可访问(核心案例)
  private _price: number;
  private _discount: number = 1;
  private _stock: number;
  
  // 构造函数(不变)
  constructor(name: string, price: number, stock: number, discount?: number, category?: string) {
    this.name = name;
    this._price = Math.max(price, 0);
    this._stock = Math.max(stock, 0);
    if (discount && discount > 0 && discount <= 1) {
      this._discount = discount;
    }
    this.category = category?.trim() || this.category;
  }

  // 实例方法(不变)
  printInfo(): void {
    const finalPrice = parseFloat((this._price * this._discount).toFixed(2));
    console.log(`
      商品名称:${this.name}
      商品分类:${this.category}
      商品原价:${this._price}元
      商品折扣:${this._discount * 10}折
      折后售价:${finalPrice}元
      商品库存:${this._stock}件
    `);
  }

  /**
   * setter:修改售价(带安全校验)
   * 语法:set + 属性名(无下划线),参数为新值
   */
  set price(newPrice: number) {
    if (newPrice < 0) {
      console.warn(`【${this.name}】售价不能为负,修改失败`);
      return;
    }
    this._price = newPrice;
    console.log(`【${this.name}】售价修改为:${newPrice}元`);
  }

  /**
   * getter:读取售价
   * 语法:get + 属性名(无下划线),无参数,返回属性值
   * 注意:getter和setter需手动成对定义,不会自动生成
   */
  get price() {
    return this._price;
  }

  // 折扣的getter/setter
  set discount(newDiscount:number) {
    if (newDiscount > 0 && newDiscount <= 1) {
      this._discount = newDiscount;
      console.log(`【${this.name}】折扣修改为:${newDiscount * 10}折`);
    } else {
      console.warn(`【${this.name}】折扣无效(需0~1之间),修改失败`);
    }
  }
  get discount(){
   return this._discount;
  }

  // 库存的getter/setter
  set stock(newStock:number) {
    if (newStock < 0) {
      console.warn(`【${this.name}】库存不能为负,修改失败`);
      return;
    }
    this._stock = newStock;
    console.log(`【${this.name}】库存修改为:${newStock}件`);
  }
  get stock(){
    return this._stock;
  }
}

四、getter/setter方法的实战与深度解析

4.1 调用测试(getter/setter)

// pages/Index.ets
import { Goods } from '../model/Goods';

@Entry
@Component
struct Index {

  aboutToAppear(): void {
    const phone = new Goods("鸿蒙Mate70手机", 5999, 100, 0.8, "数码产品");
    const watch = new Goods("鸿蒙智能手表", 1299, 50, 0.9, "穿戴设备");

    // 测试售价的getter/setter
    phone.price = -100; // 非法值:修改失败(触发setter校验)
    console.log(`第一次读取售价:${phone.price}`); // 读取:5999(触发getter)
    phone.price = 7999; // 合法值:修改成功
    console.log(`第二次读取售价:${phone.price}`); // 读取:7999

    // 测试折扣的getter/setter
    watch.discount = 1.2; // 非法值:修改失败
    console.log(`第一次读取折扣:${watch.discount * 10}折`); // 读取:9折
    watch.discount = 0.85; // 合法值:修改成功
    console.log(`第二次读取折扣:${watch.discount * 10}折`); // 读取:8.5折

    // 测试库存的getter/setter
    watch.stock = -20; // 非法值:修改失败
    console.log(`第一次读取库存:${watch.stock}件`); // 读取:50件
    watch.stock = 80; // 合法值:修改成功
    console.log(`第二次读取库存:${watch.stock}件`); // 读取:80件

    // 打印商品信息(验证售价/折扣/库存修改生效)
    phone.printInfo();
    watch.printInfo();

     /**
     * getter/setter核心特点:
     * 1. 需手动成对定义(仅get表示只读,仅set表示只写,通常成对使用)
     * 2. 访问语法与普通属性一致(对象.属性),更直观
     * 3. setter仅负责单个属性的校验与修改,符合"单一职责"
     * 4. 隐藏私有属性的真实名称(_price),降低外部依赖
     * 5. 不写get 方法直接 phone.price 读取值:undefined
     */
  }

  build() {
    Text("鸿蒙商品管理项目")
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
      .margin(20);
  }
}

打印输出

【鸿蒙Mate70手机】售价不能为负,修改失败
第一次读取售价:5999
【鸿蒙Mate70手机】售价修改为:7999元
第二次读取售价:7999

【鸿蒙智能手表】折扣无效(需0~1之间),修改失败
第一次读取折扣:9折
【鸿蒙智能手表】折扣修改为:8.5折
第二次读取折扣:8.5折

【鸿蒙智能手表】库存不能为负,修改失败
第一次读取库存:50件
【鸿蒙智能手表】库存修改为:80件
第二次读取库存:80件

// phone.printInfo() 输出:
      商品名称:鸿蒙Mate70手机
      商品分类:数码产品
      商品原价:7999元
      商品折扣:8折
      折后售价:6399.2元
      商品库存:100件

// watch.printInfo() 输出:
      商品名称:鸿蒙智能手表
      商品分类:穿戴设备
      商品原价:1299元
      商品折扣:8.5折
      折后售价:1104.15元
      商品库存:80件

4.2 getter/setter与普通方法的本质区别

特性 普通方法(如setPrice/getPrice) getter/setter方法 鸿蒙开发推荐场景
语法形式 方法调用(对象.方法名(参数) 属性操作(对象.属性 = 值/对象.属性 -
职责范围 可包含多逻辑(修改属性+日志+接口调用) 仅负责单个属性的受控读写,单一职责 -
语义表达 强调“执行动作”(如“设置售价”) 强调“操作属性”(如“修改售价属性”) -
工程规范性 无强制约束,易职责混乱 符合面向对象封装设计,语义更清晰 -
推荐场景 多逻辑组合操作(改价+同步服务器) 单个属性的简单校验(售价/库存/折扣) ✅ 优先选型

4.3 选型原则(鸿蒙开发场景)

  • 场景1:仅需受控读写单个属性(如售价、库存)→ 优先用getter/setter;
  • 场景2:需包含多逻辑(如修改属性+同步服务器+打印日志)→ 用普通方法;
  • 场景3:属性仅需“读”(如折后价)→ 仅定义getter(或普通方法);
  • 场景4:属性无需校验,直接读写→ 用public属性(无需封装)。

五、常见问题解答

5.1 类可以没有构造函数吗?

可以。ArkTS会自动生成空构造函数,但未设置默认值的属性必须在构造函数中赋值,否则编译报错:

// model/EmptyClass.ets
export class EmptyClass {
  msg: string = "默认信息"; // 设默认值,无构造函数也合法
  // 未设默认值的属性,无构造函数会报错:Property 'price' has no initializer and is not definitely assigned in the constructor.
  // price: number; 
}

// pages/Index.ets 调用测试
import { EmptyClass } from '../model/Goods';

const obj = new EmptyClass();
console.log(obj.msg); // 输出:默认信息

打印输出

默认信息

5.2 多个对象实例的属性是否相互独立?

是。每个对象拥有独立的内存空间,修改一个对象的属性不会影响其他对象:

// pages/Index.ets 调用测试
import { Goods } from '../model/Goods';

const phone = new Goods("鸿蒙Mate70手机", 5999, 100, 0.8);
const watch = new Goods("鸿蒙智能手表", 1299, 50, 0.9);

phone.price = 4999; // 仅修改phone的售价
const phoneFinalPrice = parseFloat((phone.price * phone.discount).toFixed(2));
const watchFinalPrice = parseFloat((watch.price * watch.discount).toFixed(2));

console.log(`手机折后价:${phoneFinalPrice}元`); // 输出:3999.2
console.log(`手表折后价:${watchFinalPrice}元`); // 输出:1169.1(不受phone影响)

打印输出

【鸿蒙Mate70手机】售价修改为:4999元
手机折后价:3999.2元
手表折后价:1169.1元

5.3 getter/setter必须成对定义吗?

不一定:

  • 成对定义(get+set):属性可读写(如售价);
  • 仅定义get:属性只读(如商品ID,一旦创建不可修改);
  • 仅定义set:属性只写(极少用,如临时接收数据);
  • 注意:仅定义set时,外部读取属性值,会得到undefined未定义。

// 仅定义getter(只读属性)
export class ReadOnlyClass {
  private _id: string = "GOODS_001";
  get id() {
    return this._id;
  }
}

// 仅定义setter(只写属性)
export class WriteOnlyClass {
  private _tempData: string = "";
  set tempData(data: string) {
    this._tempData = data;
    console.log(`临时数据已接收:${data}`);
  }
}

  // 调用测试
import { ReadOnlyClass } from '../model/ReadOnlyClass';
import { WriteOnlyClass } from '../model/WriteOnlyClass';

aboutToAppear(){
    const readOnlyObj = new ReadOnlyClass();
    console.log(`商品ID:${readOnlyObj.id}`); // 可读
    // readOnlyObj.id = "GOODS_002"; // 报错:Cannot assign to 'id' because it is a read-only property.

    const writeOnlyObj = new WriteOnlyClass();
    writeOnlyObj.tempData = "测试数据"; // 可写
    console.log(`临时数据读取:${writeOnlyObj.tempData}`); // 输出:undefined
}

打印输出

商品ID:GOODS_001
临时数据已接收:测试数据
临时数据读取:undefined

六、内容总结

  1. 面向对象的核心是“类(模板)+对象(实例)”,通过封装解决面向过程多实例代码冗余的问题,适配鸿蒙电商商品管理场景;
  2. ArkTS类必须遵循“先声明、后赋值”,不支持TypeScript的构造函数参数简化写法,this是访问实例属性的唯一合法方式;
  3. function关键字规则:全局函数必须加,类内部方法禁止加,否则语法报错;
  4. 封装的核心是用private隐藏敏感数据,通过getter/setter或普通方法暴露受控接口,既保证数据安全,又简化外部调用;
  5. getter/setter是属性受控读写的专用语法,比普通方法更贴合属性操作语义,优先用于单个属性的校验与读写(如鸿蒙商品的售价、库存)。

七、代码仓库

八、下节预告

  1. 下一节:类的继承与多态入门将深入学习面向对象进阶核心:
    • 类的继承规则:extends关键字、super调用父类构造/方法的核心语法;
    • protected修饰符实战:子类复用父类中间数据(如商品售价);
    • 多态入门:父类引用管理子类对象,实现鸿蒙电商商品分类逻辑的统一管理;
  2. 继承与多态是鸿蒙电商场景“商品分类管理”的核心设计思想,掌握后将为后续抽象类、接口学习打下基础。
posted @ 2026-01-22 12:20  鸿蒙-散修  阅读(1)  评论(0)    收藏  举报