HarmonyOS Next类的继承机制:单继承模型下的代码复用与扩展

在HarmonyOS Next开发中,类的继承机制是实现代码复用与多态的核心特性。通过单继承模型,子类能够继承父类的成员(除私有成员外),并通过覆盖(Override)扩展行为。本文结合文档知识点,解析继承的规则、最佳实践及在实际场景中的应用。

一、继承的基本规则与语法

HarmonyOS Next支持单继承,子类通过 <: 关键字声明继承父类,语法如下:

cj 复制代码
open class Parent { /* 父类定义 */ }
class Child <: Parent { /* 子类继承父类 */ }

1. 可继承成员与访问控制

  • 可继承成员
    • private的成员变量、成员函数、静态成员;
    • 父类的构造函数不可继承,但可通过 super() 调用。
  • 不可继承成员
    • private 成员(仅限父类内部访问);
    • 构造函数(子类需自定义)。

示例

cj 复制代码
open class Animal {
    public var name: String
    protected var age: Int // 受保护成员可被子类访问
    public init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

class Dog <: Animal {
    public var breed: String
    public init(name: String, age: Int, breed: String) {
        self.breed = breed
        super.init(name: name, age: age) // 调用父类构造函数
    }
    // 访问父类受保护成员
    public func getAge() -> Int { age }
}

2. open修饰符与继承权限

  • open类默认不可继承,需显式声明open

    cj 复制代码
    class SealedClass {} // 不可继承
    open class OpenClass {} // 可继承
  • open成员允许子类覆盖,非open成员默认不可覆盖:

    cj 复制代码
    open class Base {
        public func fixedFunc() {} // 非open,子类不可覆盖
        public open func overriddenFunc() {} // open,子类可覆盖
    }

二、构造函数的继承与调用顺序

1. 构造函数的类型

  • 主构造函数:与类同名,声明时初始化成员变量;
  • 普通构造函数 :以init声明,支持重载。

2. 子类构造函数的规则

  • 必须调用父类构造函数(super())或本类其他构造函数(this()),且需在构造函数体首行调用:

    cj 复制代码
    open class Vehicle {
        public var speed: Int
        public init(speed: Int) { self.speed = speed }
    }
    
    class Car <: Vehicle {
        public var brand: String
        public init(speed: Int, brand: String) {
            self.brand = brand
            super.init(speed: speed) // 必须首先调用父类构造函数
        }
    }
  • 若父类无无参构造函数,子类必须显式调用父类带参构造函数:

    cj 复制代码
    open class Parent {
        public init(value: Int) {} // 无默认构造函数
    }
    class Child <: Parent {
        public init() {
            super.init(value: 0) // 必须调用父类带参构造函数
        }
    }

3. 初始化顺序

  1. 初始化子类成员变量;
  2. 调用父类构造函数;
  3. 执行构造函数体逻辑。

示例

cj 复制代码
open class A {
    public var a = 10 { didSet { println("A.a = \(a)") } }
    public init() { a = 20 } // 父类构造函数修改a的值
}
class B <: A {
    public var b = a + 5 // 子类成员变量初始化时,父类a已被初始化
    public init() {
        super.init() // 调用父类构造函数(此时a=20)
        b = 30 // 进一步修改b的值
    }
}
let b = B() // 输出:A.a = 20

三、覆盖(Override)与重定义(Redef)

1. 实例函数的覆盖(Override)

子类可覆盖父类的open实例函数,需使用override修饰(可选但推荐显式声明):

cj 复制代码
open class Shape {
    public open func area(): Float64 { 0.0 } // 父类默认实现
}
class Circle <: Shape {
    private let radius: Float64
    public init(radius: Float64) { self.radius = radius }
    public override func area(): Float64 { // 覆盖父类方法
        3.14 * radius * radius
    }
}

2. 静态函数的重定义(Redef)

子类可重定义父类静态函数,使用redef修饰(可选):

cj 复制代码
open class Utility {
    public static func version(): String { "1.0" }
}
class AdvancedUtility <: Utility {
    public redef static func version(): String { "2.0" } // 重定义静态函数
}

3. 覆盖规则

  • 函数签名必须与父类完全一致(参数类型、返回值);
  • 子类成员访问修饰符需与父类一致或更宽松(如父类protected,子类可public)。

四、继承与多态的实战应用

场景:实现设备驱动框架,支持不同硬件类型的统一控制

1. 定义父类:通用设备驱动

cj 复制代码
open class DeviceDriver {
    public var deviceName: String
    public open func connect(): Bool {
        println("连接设备:\(deviceName)")
        return true // 默认实现
    }
    public init(name: String) {
        self.deviceName = name
    }
}

2. 子类:具体硬件驱动(如串口驱动、网络驱动)

cj 复制代码
class SerialDriver <: DeviceDriver {
    private let port: Int
    public override func connect(): Bool { // 覆盖连接逻辑
        println("通过串口\(port)连接设备:\(deviceName)")
        return super.connect() // 调用父类默认逻辑
    }
    public init(name: String, port: Int) {
        self.port = port
        super.init(name: name)
    }
}

class NetworkDriver <: DeviceDriver {
    private let ip: String
    public redef static func version(): String { // 重定义静态版本号
        "NetworkDriver v1.2"
    }
    public init(name: String, ip: String) {
        self.ip = ip
        super.init(name: name)
    }
}

3. 多态调用:统一接口处理不同驱动

cj 复制代码
func testDrivers() {
    let serial = SerialDriver(name: "COM1", port: 1)
    let network = NetworkDriver(name: "Server", ip: "192.168.1.1")
    
    let drivers: [DeviceDriver] = [serial, network]
    drivers.forEach { driver in
        driver.connect() // 动态调用子类实现
    }
    println(NetworkDriver.version()) // 输出重定义的静态函数结果
}

输出结果

arduino 复制代码
通过串口1连接设备:COM1
连接设备:Server
NetworkDriver v1.2

五、继承的限制与替代方案

1. 单继承限制与组合模式

  • HarmonyOS Next不支持多重继承,可通过组合接口(class <: I1 & I2)或包含对象实例实现多能力整合:

    cj 复制代码
    interface Printable { func printData() }
    interface Connectable { func connect() }
    class MultiFunctionDevice <: Printable, Connectable {
        private let printer: Printer // 组合打印机对象
        private let connector: Connector // 组合连接器对象
        public func printData() { printer.print() }
        public func connect() { connector.link() }
    }

2. sealed类与封闭设计

使用sealed修饰类,禁止其被继承,适用于工具类或最终实现类:

cj 复制代码
sealed class FinalLogger { /* 最终日志类,不可继承 */ }

3. 抽象类的继承约束

抽象类强制子类实现抽象成员,确保逻辑完整性:

cj 复制代码
abstract class AbstractParser {
    public abstract func parse(data: String): Any // 抽象函数
    public func logError(message: String) { /* 具体错误处理 */ }
}
class JSONParser <: AbstractParser {
    public override func parse(data: String): Any { /* 实现解析逻辑 */ }
}

六、总结:继承的设计权衡

HarmonyOS Next的单继承机制在保证代码结构清晰的同时,通过以下方式实现复用与扩展:

  • 代码复用:继承父类成员,避免重复实现通用逻辑;
  • 行为扩展:通过覆盖修改父类行为,或新增成员扩展能力;
  • 多态抽象:父类引用子类实例,实现统一接口下的差异化处理。
相关推荐
前端Hardy28 分钟前
HTML&CSS:3D图片切换效果
前端·javascript
spionbo1 小时前
Vue 表情包输入组件实现代码及完整开发流程解析
前端·javascript·面试
全宝1 小时前
✏️Canvas实现环形文字
前端·javascript·canvas
lyc2333331 小时前
鸿蒙Core File Kit:极简文件管理指南📁
前端
我这里是好的呀1 小时前
全栈开发个人博客12.嵌套评论设计
前端·全栈
我这里是好的呀1 小时前
全栈开发个人博客13.AI聊天设计
前端·全栈
金金金__1 小时前
Element-Plus:popconfirm与tooltip一起使用不生效?
前端·vue.js·element
lyc2333331 小时前
小L带你看鸿蒙应用升级的数据迁移适配📱
前端
用户26812851066691 小时前
react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)
前端