零基础鸿蒙应用开发第二十二节:类的继承与多态入门
【学习目标】理解继承的核心意义掌握ArkTS中extends关键字的使用规则区分“单继承”特性在鸿蒙开发中的适配场景掌握super关键字的核心作用调用父类构造函数、调用父类方法规避继承中的常见语法错误吃透protected访问修饰符的访问范围掌握其与public/private的差异及在层级类中的应用熟悉方法重写的概念理解隐式重写与显式重写的区别掌握override关键字的规范用法实现子类对父类方法的自定义扩展理解多态的核心概念父类引用指向子类对象掌握鸿蒙电商场景下父类引用管理子类对象的基础用法发现普通父类的两大局限性可直接实例化无业务意义的对象、无法强制子类实现差异化核心业务逻辑为后续学习抽象类做好铺垫实现鸿蒙电商商户端商品分类的统一管理。【学习重点】ArkTS“单继承”规则与鸿蒙开发的适配性避免多重继承的语法错误super关键字在子类构造函数中的强制调用规则参数需与父类构造函数完全对齐protected修饰符的核心应用子类访问父类的**成本价底价**字段类外不可访问方法重写的完整逻辑先掌握隐式重写无需override再理解override的规范价值明确重写的核心规则签名一致、访问修饰符约束多态的基础实现父类引用指向子类对象简化商户端商品列表的统一管理普通父类的局限性①Goods类可直接实例化无法约束商品必须属于具体子类如数码、图书②父类默认方法实现无法强制子类差异化实现核心业务逻辑如折后价计算与上一节Goods类的衔接新增costPrice属性及对应逻辑保留原有setPrice/getPrice、printInfo等核心方法仅重构折后价计算逻辑。一、工程结构本节示例代码基于上一节工程复制一份重命名为ClassObjectDemo_1工程核心结构如下ClassObjectDemo_1/ ├── entry/ # 应用主模块 │ ├── src/ │ │ ├── main/ │ │ │ ├── ets/ # ArkTS代码根目录 │ │ │ │ ├── pages/ # 页面代码目录 │ │ │ │ │ └── Index.ets # 测试页面 │ │ │ │ └── model/ # 业务模型类目录 │ │ │ │ ├── Goods.ets # 父类商品基类 │ │ │ │ ├── DigitalGoods.ets # 新增子类数码商品类 │ │ │ │ └── BookGoods.ets # 新增子类图书商品类 │ │ │ ├── resources/ # 资源目录 │ │ │ └── module.json5 # 模块配置文件 │ │ └── oh-package.json5 # 工程依赖配置 └── hvigorfile.ts # 构建脚本二、继承基础解析2.1 为什么需要继承上一节实现了通用的Goods类封装了商品的名称、价格、库存、折扣等核心属性和通用方法但电商场景中存在“数码商品”“图书商品”等细分类型共性名称、价格、库存、折扣、打印信息等个性数码商品有品牌/保修年限图书商品有作者/出版日期且需计算单件利润。若为每种商品单独写类会重复编写价格校验、折扣计算、库存管理等通用逻辑通过继承子类可复用父类Goods的所有通用属性/方法仅需实现专属逻辑大幅减少代码冗余同时保证逻辑统一。2.2 继承的标准语法ArkTS遵循单继承规则子类通过extends关键字继承父类核心语法如下// 父类通用属性与方法exportclassParentClass{publicpublicAttr:string;protectedprotectedAttr:number;privateprivateAttr:boolean;constructor(attr1:string,attr2:number){this.publicAttrattr1;this.protectedAttrattr2;this.privateAttrtrue;}publicpublicMethod():void{console.log(父类通用方法);}}// 子类继承父类并扩展专属逻辑exportclassChildClassextendsParentClass{privatechildAttr:string;constructor(attr1:string,attr2:number,childAttr:string){super(attr1,attr2);this.childAttrchildAttr;}// 隐式重写publicpublicMethod():void{super.publicMethod();console.log(子类扩展方法专属属性,this.childAttr);}}// 调用测试constchildObjnewChildClass(测试属性1,100,子类专属属性);childObj.publicMethod();打印输出父类通用方法 子类扩展方法专属属性 子类专属属性三、实战商品类的继承实现3.1 父类Goods类exportclassGoods{publicname:string;category:string商品分类;protectedcostPrice:number;private_price:number;private_stock:number;private_discount:number1;constructor(name:string,price:number,stock:number,costPrice:number,discount?:number,category?:string){this.namename;this._priceMath.max(price,0);this._stockMath.max(stock,0);this.costPriceMath.max(costPrice,0);if(discountdiscount0discount1){this.discountdiscount;}this.categorycategory?.trim()||this.category;}calculateFinalPrice():number{returnparseFloat((this._price*this.discount).toFixed(2));}printInfo():void{constfinalPricethis.calculateFinalPrice();constshowDiscountthis.discount*10;console.log(商品名称${this.name}商品分类${this.category}商品原价${this.price}元 商品折扣${showDiscount}折 折后售价${finalPrice}元 商品库存${this.stock}件);}setPrice(newPrice:number){if(newPrice0){console.warn(【${this.name}】售价不能为负修改失败);return;}this._pricenewPrice;console.log(【${this.name}】售价修改为${newPrice}元);}getPrice(){returnthis._price;}setprice(newPrice:number){if(newPrice0){console.warn(【${this.name}】售价不能为负修改失败);return;}this._pricenewPrice;console.log(【${this.name}】售价修改为${newPrice}元);}getprice(){returnthis._price;}setdiscount(newDiscount:number){if(newDiscount0newDiscount1){this._discountnewDiscount;console.log(【${this.name}】折扣修改为${newDiscount*10}折);}else{console.warn(【${this.name}】折扣无效需0~1之间修改失败);}}getdiscount(){returnthis._discount;}setstock(newStock:number){if(newStock0){console.warn(【${this.name}】库存不能为负修改失败);return;}this._stocknewStock;console.log(【${this.name}】库存修改为${newStock}件);}getstock(){returnthis._stock;}}3.2 子类DigitalGoods数码商品类// model/DigitalGoods.etsimport{Goods}from./Goods;exportclassDigitalGoodsextendsGoods{privatebrand:string;privatewarranty:number;constructor(name:string,price:number,stock:number,costPrice:number,brand:string,warranty:number,discount?:number,category?:string){super(name,price,stock,costPrice,discount,category||数码产品);this.brandbrand?.trim()||未知品牌;this.warrantyMath.max(warranty,1);}calculateProfit():number{constfinalPricethis.calculateFinalPrice();returnparseFloat((finalPrice-this.costPrice).toFixed(2));}publicprintInfo():void{super.printInfo();console.log(商品品牌${this.brand}保修年限${this.warranty}年 单件利润${this.calculateProfit()}元);}}调用测试import { DigitalGoods } from ../model/DigitalGoods; import { Goods } from ../model/Goods; Entry Component struct Index { State goodsList: Goods[] []; // 父类数组统一存储所有商品 aboutToAppear(): void { // 测试实例化数码商品 const phone new DigitalGoods(鸿蒙Mate70, 5999, 100, 4000, 华为, 2, 0.8); phone.printInfo(); } build() { Text(鸿蒙商品) .fontSize(20) .fontWeight(FontWeight.Bold) .margin(20); } }打印输出商品名称鸿蒙Mate70 商品分类数码产品 商品原价5999元 商品折扣0.8折 折后售价4799.2元 商品库存100件 商品品牌华为 保修年限2年 单件利润799.2元3.3 子类BookGoods图书商品类// model/BookGoods.etsimport{Goods}from./Goods;exportclassBookGoodsextendsGoods{privateauthor:string;privatepublishDate:string;constructor(name:string,price:number,stock:number,costPrice:number,author:string,publishDate:string,discount?:number,category?:string){super(name,price,stock,costPrice,discount,category||图书);this.authorauthor?.trim()||未知作者;this.publishDatepublishDate?.trim()||未知日期;}calculateBookProfit():number{constfinalPricethis.calculateFinalPrice();returnparseFloat((finalPrice-this.costPrice).toFixed(2));}publicprintInfo():void{super.printInfo();console.log(图书作者${this.author}出版日期${this.publishDate}单件利润${this.calculateBookProfit()}元);}getAuthorInfo():string{return《${this.name}》的作者是${this.author};}}调用测试import{BookGoods}from../model/BookGoods;// 测试实例化图书商品constbooknewBookGoods(鸿蒙开发实战,69,500,30,鸿蒙官方,2025-01,0.7);book.printInfo();console.log(book.getAuthorInfo());打印输出商品名称鸿蒙开发实战 商品分类图书 商品原价69元 商品折扣0.7折 折后售价48.3元 商品库存500件 图书作者鸿蒙官方 出版日期2025-01 单件利润18.3元 《鸿蒙开发实战》的作者是鸿蒙官方四、核心关键字与访问修饰符解析4.1super关键字的核心作用super是子类与父类交互的唯一入口核心用法如下作用场景语法格式核心说明调用父类构造函数super(参数1, 参数2, ...)1. 必须放在子类构造函数第一行2. 参数需与父类构造函数完全对齐3. 未调用会直接编译报错。调用父类普通方法super.方法名(参数)在子类重写的方法中复用父类原有逻辑。错误示例// 错误1未调用super()直接初始化子类属性classErrorDigitalextendsGoods{constructor(){this.brand华为;}}// 错误2super参数与父类构造函数不匹配classErrorBookextendsGoods{constructor(name:string,price:number,stock:number){super(name,price,stock);}}4.2protected访问修饰符修饰符父类内访问子类内访问类外访问应用场景public✅✅✅name、category、printInfo等protected✅✅❌costPriceprivate✅❌❌_price、_stock、_discount等实战验证constphonenewDigitalGoods(鸿蒙Mate70,5999,100,4000,华为,2);console.log(利润,phone.calculateProfit());console.log(phone.name);// console.log(phone.costPrice);// console.log(phone._price);4.3 重写核心规则方法签名必须与父类一致访问修饰符权限不能缩小子类重写时可通过super调用父类原逻辑父类私有方法无法被重写。4.4 显式重写添加override关键字提升可读性与安全性,方便其他开发人员看见override关键字立刻知道这是重写方法。public override printInfo(): void { super.printInfo(); console.log( 图书作者${this.author} 出版日期${this.publishDate} 单件利润${this.calculateBookProfit()}元 ); }隐式重写的缺点其他开发人员想要确定这是重写方法需查看父类。辨识度较低修改父类方法后隐式重写可能会变成子类独有方法。错误示例// 错误1方法签名不一致 public printInfo(format: boolean): void { super.printInfo(); } // 错误2访问修饰符权限缩小 protected printInfo(): void { super.printInfo(); }4.4 继承的核心规则单继承规则ArkTS不支持多重继承如class A extends B, C会直接编译报错属性继承规则子类仅继承父类的public和protected属性/方法扩展性规则新增商品类型仅需继承Goods类扩展专属逻辑普通父类的潜在问题可直接实例化无业务意义的纯商品对象父类的calculateFinalPrice方法为固定实现无法强制子类差异化实现隐式重写无编译器校验易出现“伪重写”导致多态逻辑失效。五、多态入门5.1 多态的本质多态的本质是“接口统一实现各异”父类定义了统一的方法接口子类通过重写提供不同的实现通过父类引用调用时会根据实际指向的子类对象执行对应的实现。5.2 多态三要素继承子类继承父类方法重写子类重写父类通用方法父类引用用Goods类型存储子类实例。5.3 多态的工程化实现// pages/Index.ets import { Goods } from ../model/Goods; import { DigitalGoods } from ../model/DigitalGoods; import { BookGoods } from ../model/BookGoods; Entry Component struct Index { aboutToAppear(): void { const digital: Goods new DigitalGoods(鸿蒙Mate70手机, 5999, 100, 4000, 华为, 2, 0.8, 数码产品); const book: Goods new BookGoods(鸿蒙开发实战, 69, 500, 30, 鸿蒙官方, 2025-01, 0.7, 图书); const invalid: Goods new Goods(鸿蒙智能手表, 1299, 80, 800, 0.9, 穿戴设备); const goodsList: Goods[] [digital, book, invalid]; goodsList.forEach((goods, index) { console.log(\n 商品${index 1}信息 ); goods.printInfo(); }); this.batchUpdateStock(goodsList, 50); this.calculateTotalStock(goodsList); if (book instanceof BookGoods) { console.log(\n book.getAuthorInfo()); } } private batchUpdateStock(goodsList: Goods[], num: number): void { console.log(\n 批量增加${num}件商品库存 ); goodsList.forEach(goods { goods.stock goods.stock num; }); } private calculateTotalStock(goodsList: Goods[]): void { const total goodsList.reduce((sum, goods) sum goods.stock, 0); console.log(\n 所有商品总库存${total} ); } build() { Column() { Text(鸿蒙电商商品管理-继承与多态) .fontSize(20) .fontWeight(FontWeight.Bold) .margin(20); } .width(100%) .height(100%) .justifyContent(FlexAlign.Center); } }打印输出【鸿蒙Mate70手机】折扣修改为8折 【鸿蒙开发实战】折扣修改为7折 【鸿蒙智能手表】折扣修改为9折 商品1信息 商品名称鸿蒙Mate70手机 商品分类数码产品 商品原价5999元 商品折扣8折 折后售价4799.2元 商品库存100件 商品品牌华为 保修年限2年 单件利润799.2元 商品2信息 商品名称鸿蒙开发实战 商品分类图书 商品原价69元 商品折扣7折 折后售价48.3元 商品库存500件 图书作者鸿蒙官方 出版日期2025-01 单件利润18.3元 商品3信息 商品名称鸿蒙智能手表 商品分类穿戴设备 商品原价1299元 商品折扣9折 折后售价1169.1元 商品库存80件 批量增加50件商品库存 【鸿蒙Mate70手机】库存修改为150件 【鸿蒙开发实战】库存修改为550件 【鸿蒙智能手表】库存修改为130件 所有商品总库存830 《鸿蒙开发实战》的作者是鸿蒙官方5.4 多态的核心优势代码简洁无需用if-else判断商品类型统一通过父类接口操作扩展性极强新增商品类型无需修改原有批量操作、统计逻辑显式重写提升稳定性使用override关键字可避免“伪重写”暴露普通父类的设计缺陷可实例化无业务意义的纯商品对象父类默认方法实现无法强制子类差异化实现核心业务逻辑。六、常见问题解答6.1 为什么不建议直接实例化Goods类从业务逻辑看商品必须是具体类型不存在“无类型的纯商品”从技术角度看直接实例化会导致代码约束性差容易出现不符合业务规则的对象纯商品对象的calculateFinalPrice方法使用父类默认实现无法适配后续差异化的定价逻辑。6.2 父类引用如何调用子类专属方法父类引用需通过类型断言判断类型符合条件直接调用子类专属方法if(bookinstanceofBookGoods){book.getAuthorInfo();}6.3 隐式重写和显式重写的区别是什么对比维度隐式重写显式重写写法难度简单稍复杂可读性差好编译器校验无有维护成本高低工程化推荐度不推荐强烈推荐6.4 为什么父类的calculateFinalPrice方法不适合所有商品类型父类的calculateFinalPrice仅实现了“售价×折扣系数”的固定逻辑但不同商品存在差异化的定价需求如叠加满减活动、结合会员折扣该方法无法满足这些多样化的业务需求。七、内容总结继承的核心是代码复用与逻辑统一子类通过extends继承父类需先调用super()初始化父类必传属性protected修饰符实现了父子类之间的数据共享方法重写有两种实现方式隐式重写和显式重写核心规则是签名一致、访问修饰符不能更严格可通过super复用父类逻辑多态通过父类引用指向子类对象实现对不同实体商品的统一管理显式重写能提升多态逻辑的稳定性新增商品类型仅需扩展子类扩展性极强普通父类存在两大核心局限性可直接实例化无业务意义的对象、默认方法实现无法强制子类差异化实现核心业务逻辑这两个问题将在下一节通过抽象类与抽象方法解决。八、代码仓库工程名称ClassObjectDemo_1仓库地址https://gitee.com/juhetianxia321/harmony-os-code-base.git九、下节预告本节我们已经掌握了继承的核心用法、super关键字与protected修饰符的应用以及方法重写和多态的基础实现逻辑也明确了普通父类的两大局限性。下一节我们将针对这些问题展开进阶学习深入探索抽象类的核心知识与实战应用核心内容包括抽象类的定义与实战将Goods基类改造为AbstractGoods抽象类从语法层面禁止直接实例化无业务意义的对象抽象方法的声明与实现将calculateFinalPrice改为抽象方法强制子类实现差异化的定价逻辑解决业务约束问题抽象类多态的进阶应用新增商品子类虚拟类商品实现抽象类引用管理所有商品对象并结合鸿蒙ArkUI完成商品列表的UI渲染抽象类与普通类的核心差异从语法、业务、工程化三个维度对比明确抽象类在鸿蒙电商架构中的选型逻辑。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2475986.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!