零基础鸿蒙应用开发第二十六节:泛型与商品容器的灵活适配
【学习目标】
- 聚焦泛型在电商商品管理场景的实战落地,完成通用商品容器的设计与实现,落地商品统一增删查改、多维度排序筛选能力;
- 熟练运用
<T extends AbstractGoods>泛型约束语法,在保障类型安全的前提下,实现数码/图书等多品类商品的通用化管理; - 封装泛型工具类,解决不同商品类型管理逻辑冗余的问题,提升代码复用性与工程化程度;
- 整合“抽象类+属性契约+行为契约+泛型”四层架构,完成电商商品模块的工程化闭环;
【学习重点】
- 实战核心:聚焦
T extends AbstractGoods在商品容器中的应用,解决多品类商品管理的复用性与类型安全问题; - 容器设计:用泛型类实现商品统一增删查改,适配所有商品子类,避免为不同品类重复编写管理逻辑;
- 工具封装:通过“泛型方法+比较器接口”实现商品排序/筛选,聚焦业务逻辑而非语法本身;
- 架构整合:将泛型作为通用管理层,承接前序的抽象类与契约体系,形成完整的商品管理链路;
- 交互验证:通过鸿蒙UI联动泛型能力,验证商品管理逻辑的正确性,而非关注UI布局规范。
一、工程结构
复制上一节的ClassObjectDemo_4工程,重命名为ClassObjectDemo_5,聚焦商品管理能力扩展,重构目录结构如下:
ClassObjectDemo_5/
├── entry/ # 应用主模块
│ ├── src/main/ets/
│ │ ├── pages/ # 视图层:仅存放UI交互
│ │ │ └── Index.ets # 测试页面:泛型商品管理实战+UI交互
│ │ ├── model/ # 核心模型层
│ │ │ ├── entity/ # 实体层:核心数据结构
│ │ │ │ ├── AbstractGoods.ets # 抽象商品基类
│ │ │ │ ├── DigitalGoods.ets # 数码商品子类
│ │ │ │ ├── BookGoods.ets # 图书商品子类
│ │ │ │ └── GoodsStatus.ets # 商品状态枚举
│ │ │ ├── interface/ # 契约层:属性/行为/比较器接口
│ │ │ │ ├── attribute/ # 属性契约
│ │ │ │ │ ├── IBaseGoods.ets
│ │ │ │ │ ├── IDigitalGoods.ets
│ │ │ │ │ └── IBookGoods.ets
│ │ │ │ ├── behavior/ # 行为契约
│ │ │ │ │ ├── IDiscountable.ets
│ │ │ │ │ ├── IFullReductionable.ets
│ │ │ │ │ ├── IReturnable.ets
│ │ │ │ │ └── IGoodsComparator.ets # 泛型比较器接口
│ │ │ │ └── promotion/ # 促销契约
│ │ │ │ ├── IPromotionRule.ets
│ │ │ │ ├── IDiscountRule.ets
│ │ │ │ └── IFullReductionRule.ets
│ │ │ ├── comparator/ # 比较器实现(排序规则)
│ │ │ │ ├── StockAscComparator.ets # 库存升序
│ │ │ │ ├── StockDescComparator.ets # 库存降序
│ │ │ │ └── PriceAscComparator.ets # 价格升序
│ │ │ └── utils/ # 泛型工具层
│ │ │ ├── GoodsList.ets # 泛型商品容器(增删查改)
│ │ │ ├── GoodsTool.ets # 泛型工具类(排序/筛选)
│ │ │ └── PromotionValidator.ets # 复用:促销规则校验
│ ├── resources/ # 资源目录(默认生成)
│ └── module.json5 # 模块配置(默认生成)
└── hvigorfile.ts # 构建脚本(默认生成)
二、泛型的实战价值:解决商品管理的核心痛点
在上一节的数码/图书商品体系中,若为不同商品类型单独编写管理逻辑,会出现代码冗余、类型固化、扩展困难三大问题:
- 冗余:数码/图书商品的添加、删除、查询逻辑100%重复,仅类型不同;
- 固化:新增食品/服饰等商品类型时,需重复开发全套管理逻辑;
- 泛型的实战解决思路:
通过<T extends AbstractGoods>将类型参数化,一套逻辑适配所有商品子类,既保留“数码/图书”的类型区分,又复用管理逻辑,兼顾“复用性+类型安全”——这是泛型在电商商品管理场景的核心价值。
说明:第十五节已学习泛型核心知识,本节聚焦实战落地,不再重复基础语法。
三、泛型商品容器
3.1 统一管理所有商品(增删查改)
基于泛型实现通用商品容器,核心解决“多品类商品管理逻辑复用”问题(优化:按商品唯一ID判重,符合业务实际):
// model/utils/GoodsList.ets
import { AbstractGoods } from '../entity/AbstractGoods';
/**
* 泛型商品容器:适配所有AbstractGoods子类(数码/图书/新增品类)
* 核心:无需为不同商品类型单独编写增删查改逻辑
*/
export class GoodsList<T extends AbstractGoods> {
// 私有列表:对外仅返回副本,保障数据安全
private readonly goodsList: T[] = [];
/**
* 添加单个商品(按goodsId判重,避免重复添加)
*/
public addGoods(item: T): boolean {
if (!item) {
console.warn("【GoodsList】添加失败:商品实例为空");
return false;
}
if (this.goodsList.some(g => g.goodsId === item.goodsId)) {
console.warn(`【GoodsList】添加失败:goodsId=${item.goodsId}的商品已存在`);
return false;
}
this.goodsList.push(item);
console.log(`【GoodsList】成功添加:${item.name}(goodsId=${item.goodsId})`);
return true;
}
/**
* 批量添加商品(自动过滤无效/重复项)
*/
public addGoodsBatch(items: T[]): number {
if (!Array.isArray(items) || items.length === 0) {
return 0;
}
const validItems = items.filter(item => item && !this.goodsList.some(g => g.goodsId === item.goodsId));
this.goodsList.push(...validItems);
console.log(`【GoodsList】批量添加成功:共${validItems.length}件商品`);
return validItems.length;
}
/**
* 删除商品(按唯一goodsId)
*/
public removeGoodsById(id: string): boolean {
const index = this.goodsList.findIndex(g => g.goodsId === id);
if (index === -1) {
console.warn(`【GoodsList】删除失败:未找到goodsId为${id}的商品`);
return false;
}
this.goodsList.splice(index, 1);
console.log(`【GoodsList】成功删除:goodsId=${id}的商品`);
return true;
}
/**
* 按ID精准查询商品(返回副本,不篡改原数据)
* 核心:适配List的精准查询场景,与getGoodsByName/ByCategory形成完整查询体系
*/
public getGoodsById(id: string): T | undefined {
const matchedGoods = this.goodsList.find(g => g.goodsId === id);
return matchedGoods
}
/**
* 修改商品库存(核心业务能力)
*/
public updateGoodsStock(id: string, newStock: number): boolean {
const targetGoods = this.goodsList.find(g => g.goodsId === id);
if (!targetGoods) {
console.warn(`【GoodsList】修改失败:未找到goodsId为${id}的商品`);
return false;
}
targetGoods.stock = newStock;
console.log(`【GoodsList】${targetGoods.name}库存已更新为:${newStock}`);
return true;
}
// 按名称查询商品模糊查找
public getGoodsByName(name: string): T[] {
// 过滤名称包含目标字符串的商品(不区分大小写)
const matchedGoods = this.goodsList.filter(goods =>
goods.name.toLowerCase().includes(name.toLowerCase())
);
// 返回副本,避免外部篡改,同时做泛型类型转换
const result = [...matchedGoods] as T[];
console.log(`根据名称"${name}"查询到${result.length}个商品`);
return result;
}
// 按分类筛选商品
public getGoodsByCategory(category: string): T[] {
const trimCategory = category?.trim();
if (!trimCategory) {
return [];
}
return this.goodsList.filter(g => g.category === trimCategory);
}
// 获取商品列表(返回副本,避免外部修改原数据)
public getGoodsList(): T[] {
return [...this.goodsList];
}
// 获取商品总数
public getCount(): number {
return this.goodsList.length;
}
// 清空列表
public clear(): void {
if (this.goodsList.length > 0) {
this.goodsList.length = 0;
console.log("【GoodsList】商品列表已清空");
}
}
}
3.2 泛型比较器接口:定义排序规范
复用泛型接口语法,为商品排序提供统一规范:
// model/interface/behavior/IGoodsComparator.ets
import { AbstractGoods } from '../../entity/AbstractGoods';
/**
* 泛型比较器接口:统一商品排序规则的定义规范
*/
export interface IGoodsComparator<T extends AbstractGoods> {
/**
* 比较两个商品
* @returns a<b返回负数,a>b返回正数,相等返回0
*/
compare(a: T, b: T): number;
}
3.3 比较器实现:聚焦排序业务规则
基于泛型比较器接口,实现库存/价格排序规则:当然你也可以自己拓展补充。
库存升序
// model/comparator/StockAscComparator.ets
import { AbstractGoods } from '../entity/AbstractGoods';
import { IGoodsComparator } from '../interface/behavior/IGoodsComparator';
/**
* 库存升序比较器:业务规则→库存小的商品排在前面
*/
export class StockAscComparator implements IGoodsComparator<AbstractGoods> {
compare(a: AbstractGoods, b: AbstractGoods): number {
return a.stock - b.stock;
}
}
库存降序
// model/comparator/StockDescComparator.ets
import { AbstractGoods } from '../entity/AbstractGoods';
import { IGoodsComparator } from '../interface/behavior/IGoodsComparator';
/**
* 库存降序比较器:业务规则→库存大的商品排在前面
*/
export class StockDescComparator implements IGoodsComparator<AbstractGoods> {
compare(a: AbstractGoods, b: AbstractGoods): number {
return b.stock - a.stock;
}
}
价格升序
// model/comparator/PriceAscComparator.ets
import { AbstractGoods } from '../entity/AbstractGoods';
import { IGoodsComparator } from '../interface/behavior/IGoodsComparator';
/**
* 价格升序比较器:业务规则→价格低的商品排在前面
*/
export class PriceAscComparator implements IGoodsComparator<AbstractGoods> {
compare(a: AbstractGoods, b: AbstractGoods): number {
return a.price - b.price;
}
}
3.4 泛型工具类:封装排序/筛选能力
用静态泛型方法封装商品筛选/排序,核心解决“多维度数据操作复用”问题:
知识补充:
static修饰方法时表示静态方法,需通过类名.方法名调用,无需实例化类;静态方法天然适配工具类的“无状态、通用能力”特性。(下一节重点讲解)
// model/utils/GoodsTool.ets
import { AbstractGoods } from '../entity/AbstractGoods';
import { IGoodsComparator } from '../interface/behavior/IGoodsComparator';
/**
* 泛型商品工具类:封装通用的排序/筛选能力
*/
export class GoodsTool {
/**
* 筛选有库存商品
*/
static filterInStock<T extends AbstractGoods>(goodsList: T[]): T[] {
if (!Array.isArray(goodsList)) return [];
return goodsList.filter(g => g && g.stock > 0);
}
/**
* 价格区间筛选
*/
static filterByPriceRange<T extends AbstractGoods>(goodsList: T[], minPrice: number, maxPrice: number): T[] {
if (!Array.isArray(goodsList) || minPrice > maxPrice) return [];
const validMin = Math.max(minPrice, 0);
const validMax = Math.max(maxPrice, 0);
return goodsList.filter(g => g && g.price >= validMin && g.price <= validMax);
}
/**
* 自定义比较器排序(返回副本,不修改原数据)
*/
static sortByComparator<T extends AbstractGoods>(goodsList: T[], comparator: IGoodsComparator<T>): T[] {
if (!Array.isArray(goodsList) || !comparator) return [];
const validGoods = goodsList.filter(g => !!g);
return [...validGoods].sort((a, b) => comparator.compare(a, b));
}
}
四、通过UI交互验证
4.1 联动泛型能力与UI交互
(UI仅为验证逻辑,无需关注布局规范;整合上一节促销规则,体现架构闭环)
import { AbstractGoods } from '../model/entity/AbstractGoods';
import { DigitalGoods } from '../model/entity/DigitalGoods';
import { BookGoods } from '../model/entity/BookGoods';
import { GoodsStatus } from '../model/entity/GoodsStatus';
import { GoodsList } from '../model/utils/GoodsList';
import { GoodsTool } from '../model/utils/GoodsTool';
import { StockAscComparator } from '../model/comparator/StockAscComparator';
import { StockDescComparator } from '../model/comparator/StockDescComparator';
import { PriceAscComparator } from '../model/comparator/PriceAscComparator';
import { prompt } from '@kit.ArkUI';
import { LengthMetrics } from '@kit.ArkUI';
import { IDigitalGoods } from '../model/interface/attribute/IDigitalGoods';
import { IBookGoods } from '../model/interface/attribute/IBookGoods';
import { IDiscountRule } from '../model/interface/promotion/IDiscountRule';
@Entry
@Component
struct Index {
@State goodsList: AbstractGoods[] = [];
@State inputStock: number = 0;
@State inputName: string = '';
private goodsContainer = new GoodsList<AbstractGoods>();
// 页面初始化:加载商品(含促销规则,整合前序内容)
aboutToAppear(): void {
const initGoodsList = this.initGoods();
this.goodsContainer.addGoodsBatch(initGoodsList);
this.goodsList = this.goodsContainer.getGoodsList();
}
// 初始化商品(整合促销规则,体现四层架构)
private initGoods(): AbstractGoods[] {
// 数码商品(带8折促销)
const digitalProps: IDigitalGoods = {
name: "鸿蒙Mate70手机",
price: 5999,
stock: 100,
costPrice: 4000,
category: "数码产品",
status: GoodsStatus.ON_SHELF,
brand: "华为",
warranty: 2
};
const digitalGoods = new DigitalGoods(digitalProps);
const discountRule: IDiscountRule = {
promotionId: "discount_digital_001",
promotionName: "双十二数码会员8折",
startTime: new Date(),
endTime: new Date(2025, 11, 31),
isEnabled: true,
discountRate: 0.8,
isMemberExclusive: true
};
digitalGoods.setDiscountRule(discountRule);
// 鸿蒙平板(无促销)
const tabletProps: IDigitalGoods = {
name: "鸿蒙平板Pro",
price: 3999,
stock: 80,
costPrice: 2500,
category: "数码产品",
status: GoodsStatus.ON_SHELF,
brand: "华为",
warranty: 2
};
const tabletGoods = new DigitalGoods(tabletProps);
// 图书商品(带7折促销)
const bookProps: IBookGoods = {
name: "鸿蒙开发实战",
price: 69,
stock: 500,
costPrice: 30,
category: "图书",
status: GoodsStatus.ON_SHELF,
author: "散修",
publishDate: "2025-01"
};
const bookGoods = new BookGoods(bookProps);
const bookDiscountRule: IDiscountRule = {
promotionId: "discount_book_001",
promotionName: "图书全场7折",
startTime: new Date(),
endTime: new Date(2025, 11, 31),
isEnabled: true,
discountRate: 0.7,
isMemberExclusive: false
};
bookGoods.setDiscountRule(bookDiscountRule);
return [digitalGoods, tabletGoods, bookGoods];
}
// 库存升序排序
private sortStockAsc(): void {
this.goodsList = GoodsTool.sortByComparator(this.goodsList, new StockAscComparator());
}
// 库存降序排序
private sortStockDesc(): void {
this.goodsList = GoodsTool.sortByComparator(this.goodsList, new StockDescComparator());
}
// 价格升序排序
private sortPriceAsc(): void {
this.goodsList = GoodsTool.sortByComparator(this.goodsList, new PriceAscComparator());
}
// 筛选有库存商品
private filterInStock(): void {
this.goodsList = GoodsTool.filterInStock(this.goodsList);
}
// 筛选数码类商品
private filterDigital(): void {
this.goodsList = this.goodsContainer.getGoodsByCategory("数码产品");
}
// 重置列表
private resetList(): void {
this.goodsContainer.clear();
this.goodsContainer.addGoodsBatch(this.initGoods());
this.goodsList = this.goodsContainer.getGoodsList();
this.inputName = '';
this.inputStock = 0;
prompt.showToast({ message: "列表已重置为初始状态" });
}
// 修改库存(增加合法性校验)
private updateStock(id: string, stock: number): void {
if (stock < 0) {
prompt.showToast({ message: "库存不能为负数" });
return;
}
const success = this.goodsContainer.updateGoodsStock(id, stock);
success ? prompt.showToast({ message: "库存修改成功" }) : prompt.showToast({ message: "库存修改失败" });
this.goodsList = this.goodsContainer.getGoodsList();
}
// 删除商品
private deleteGoods(id: string): void {
const success = this.goodsContainer.removeGoodsById(id);
success ? prompt.showToast({ message: "商品删除成功" }) : prompt.showToast({ message: "商品删除失败" });
this.goodsList = this.goodsContainer.getGoodsList();
}
// 按名称查找商品
private findGoodsByName(): void {
if (!this.inputName.trim()) {
this.goodsList = this.goodsContainer.getGoodsList();
prompt.showToast({ message: "请输入商品名称" });
return;
}
const goods = this.goodsContainer.getGoodsByName(this.inputName);
this.goodsList = goods;
if (!goods) prompt.showToast({ message: `未找到【${this.inputName}】` });
}
build() {
Column() {
// 页面标题
Text("泛型商品管理实战")
.fontSize(22)
.fontWeight(FontWeight.Bold)
.margin(20);
// 商品名称查询区
Row({ space: 10 }) {
TextInput({ placeholder: "输入商品名", text: this.inputName })
.width(150)
.onChange(val => this.inputName = val);
Button("查找商品")
.onClick(() => this.findGoodsByName());
}.margin({ bottom: 15 })
// 排序/筛选按钮组
Flex({
space: { main: LengthMetrics.vp(10), cross: LengthMetrics.vp(10) },
wrap: FlexWrap.Wrap,
justifyContent: FlexAlign.Center
}) {
Button("库存升序").onClick(() => this.sortStockAsc());
Button("库存降序").onClick(() => this.sortStockDesc());
Button("价格升序").onClick(() => this.sortPriceAsc());
Button("筛选有库存").onClick(() => this.filterInStock());
Button("筛选数码商品").onClick(() => this.filterDigital());
Button("重置列表").onClick(() => this.resetList());
}.margin({ bottom: 15 });
// 商品列表展示
Scroll() {
Column({ space: 10 }) {
ForEach(this.goodsList, (goods: AbstractGoods) => {
Column({ space: 8 }) {
Row(){
Text(goods.name).fontSize(18).fontWeight(FontWeight.Medium);
Text(`${goods.status === GoodsStatus.ON_SHELF ? '在售':'已下架'}`).fontSize(14).fontColor('#666');
}
Text(`分类:${goods.category} | 价格:¥${goods.price.toFixed(2)} | 库存:${goods.stock}件`)
.fontSize(14)
.fontColor(goods.stock === 0 ? Color.Red : '#666');
// 数码商品专属信息
if (goods instanceof DigitalGoods) {
Text(`品牌:${goods.brand} | 质保:${goods.warranty}年`).fontSize(12).fontColor('#999');
}
// 图书商品专属信息
if (goods instanceof BookGoods) {
Text(`作者:${goods.author} | 出版日期:${goods.publishDate}`).fontSize(12).fontColor('#999');
}
// 操作按钮
Row({ space: 8 }) {
Button("删除商品")
.backgroundColor("#F87272")
.fontColor(Color.White)
.borderRadius(6)
.onClick(() => this.deleteGoods(goods.goodsId));
TextInput({ placeholder: "库存", text: `${goods.stock}` })
.type(InputType.Number)
.width(70)
.onChange(val => this.inputStock = isNaN(Number(val)) ? 0 : Number(val));
Button("修改库存")
.onClick(() => this.updateStock(goods.goodsId, this.inputStock));
}.width('100%')
}
.width('90%')
.padding(15)
.backgroundColor(Color.White)
.borderRadius(10)
.shadow({ radius: 5, color: '#ccc', offsetX: 2, offsetY: 2 }) // 样式仅为美观
})
}.width('100%').padding(10)
}
.layoutWeight(1)
.width('100%')
}
.width('100%')
.height('100%')
.backgroundColor('#f5f5f5')
.padding(10);
}
}
4.2 交互亮点
- 全链路数据管控:泛型容器统一管理商品增删改查,对外仅返回数据副本,避免外部篡改;
- 多维度操作:支持库存/价格排序、分类/库存筛选,一套泛型逻辑适配所有商品类型;
- 数据安全:库存修改校验负数、添加商品按ID判重,避免非法数据录入;
- 架构闭环:整合前序的促销规则,体现“属性契约→抽象类→泛型管理→UI交互”的完整链路。
运行效果

五、架构整合逻辑
graph LR
%% 基础契约层(复用二十三节)
A[属性契约层<br/>IBaseGoods/IDigitalGoods等<br/>定义:商品固有属性规范] --> B[抽象类层<br/>AbstractGoods<br/>封装:通用属性复用/基础逻辑校验/抽象方法定义]
C[促销规则契约层<br/>IPromotionRule/IDiscountRule等<br/>定义:促销规则数据规范] --> D[规则校验工具层<br/>PromotionValidator<br/>统一:规则合法性校验]
%% 行为契约层(拆分促销/排序接口,分工更清晰)
E1[行为契约-促销接口<br/>IDiscountable/IFullReductionable<br/>定义:商品促销行为规范] --> F[商品子类层<br/>DigitalGoods/BookGoods<br/>实现:多行为契约+动态规则注入+差异化业务逻辑]
E2[行为契约-排序接口<br/>IGoodsComparator<br/>定义:商品排序规则规范] --> K[比较器实现层<br/>StockAsc/PriceAsc等<br/>实现:排序规则落地]
%% 新增:泛型通用管理层(二十四节核心)
B --> H[泛型约束层<br/>T extends AbstractGoods<br/>保障:类型安全+多品类适配]
H --> I[泛型容器层<br/>GoodsList<br/>封装:商品统一增删查改]
H --> J[泛型工具层<br/>GoodsTool<br/>封装:商品排序/筛选通用能力]
%% 核心依赖链路(复用+新增)
B --> F
D --> F
F --> I
I --> J
J --> K
E2 --> J
I & J & F --> G[UI交互层<br/>Index.ets<br/>可视化:泛型能力验证+促销/排序操作]
六、内容总结
- 泛型核心价值:通过
T extends AbstractGoods的泛型约束,实现“一套管理逻辑适配所有商品子类”,既保证类型安全,又解决多品类商品管理的代码冗余问题; - 核心组件分工:泛型容器(
GoodsList)负责商品增删查改、泛型工具类(GoodsTool)负责排序/筛选入口、比较器负责具体排序规则,三层组件覆盖商品管理全场景; - 工程化价值:新增商品品类(如食品、服饰)时,仅需实现
AbstractGoods子类,无需修改泛型相关代码,大幅降低维护成本。
七、代码仓库
- 工程名称:
ClassObjectDemo_5 - 仓库地址:https://gitee.com/juhetianxia321/harmony-os-code-base.git
八、下节预告
本节课基于泛型实现了单页面商品管理,但创建多个GoodsList实例时,数据无法同步。
下一节将聚焦静态成员+单例模式,基于本节的泛型容器升级为全应用唯一的商品管理中枢:
- 静态成员:为泛型容器添加静态属性/方法,实现全局复用的商品校验、规则配置能力;
- 单例模式:改造
GoodsList为GoodsManager,保证全应用仅一个实例,解决多页面数据不一致问题; - 深度整合:泛型(类型安全)+ 静态(全局复用)+ 单例(数据一致),完成工程化商品管理体系。
浙公网安备 33010602011771号