仓颉语言中的类、接口与属性
仓颉编程语言作为一门现代化的多范式编程语言,提供了面向对象编程的核心特性,包括类(class)、接口(interface)和属性(property)等。这些特性共同构成了仓颉语言面向对象编程的基础设施,使开发者能够构建模块化、可复用且类型安全的代码。本文将详细介绍仓颉语言中这三个核心概念的定义、特性及使用方法。
一、类(Class)
1.1 类的基本概念
在仓颉语言中,**类(class)**是面向对象编程的基本构建块,用于定义对象的蓝图。类可以包含成员变量、成员属性、构造函数、成员函数等多种成员。与struct的主要区别在于:class是引用类型,struct是值类型;class之间可以继承,而struct之间不能继承。
类的基本定义语法如下:
class 类名 {
// 成员变量
// 构造函数
// 成员函数
// 成员属性
}
1.2 类的定义与成员
一个典型的类定义示例如下:
class Rectangle {
// 成员变量
let width: Int64
let height: Int64
// 构造函数
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
}
// 成员函数
public func area(): Int64 {
return width * height
}
}
在这个例子中:
width
和height
是成员变量init
是构造函数area()
是成员函数
1.3 构造函数
仓颉中的类可以有多个构造函数,用于以不同方式初始化对象。构造函数使用init
关键字定义:
class Person {
var name: String
var age: Int64
// 主构造函数
public init(name: String, age: Int64) {
this.name = name
this.age = age
}
// 辅助构造函数
public init(name: String) {
this.init(name, 0)
}
}
1.4 抽象类
使用abstract
修饰的类为抽象类,与普通类不同的是,抽象类中可以声明抽象函数(没有函数体)。抽象类的子类必须实现这些抽象函数:
abstract class Shape {
// 抽象函数
public abstract func area(): Float64
}
class Circle <: Shape {
var radius: Float64
public override func area(): Float64 {
return 3.14 * radius * radius
}
}
1.5 This类型
在类内部,支持使用This
类型占位符,代指当前类的类型。它只能作为实例成员函数的返回类型使用:
open class C1 {
func f(): This { // 返回类型为C1
return this
}
}
class C2 <: C1 {
// 继承的f()函数现在返回类型为C2
}
二、接口(Interface)
2.1 接口的基本概念
**接口(interface)**是仓颉语言中定义抽象类型的方式,它可以包含成员函数、操作符重载函数和成员属性,要求实现类型必须拥有对应的成员实现。通过接口,可以对一系列类型约定共同的功能,达到对功能进行抽象的目的。
接口的定义语法如下:
interface 接口名 {
// 抽象成员
}
2.2 接口的定义与实现
一个简单的接口定义示例:
interface Drawable {
func draw(): Unit
}
类型可以通过<:
语法实现接口:
class Circle <: Drawable {
public func draw(): Unit {
println("Drawing a circle")
}
}
2.3 接口的成员
接口可以包含三种成员:
- 成员函数
- 操作符重载函数
- 成员属性
interface Calculable {
// 成员函数
func calculate(): Int64
// 操作符重载
operator func +(other: Self): Self
// 成员属性
prop value: Int64
}
2.4 接口的默认实现
接口的成员可以提供默认实现:
interface Greetable {
func greet() {
println("Hello!")
}
}
class Person <: Greetable {
// 可以选择不实现greet(),使用默认实现
}
class CustomPerson <: Greetable {
// 也可以选择提供自己的实现
public func greet() {
println("Hi there!")
}
}
2.5 接口的多继承
一个类型可以实现多个接口,使用&
分隔:
interface A { func a(): Unit }
interface B { func b(): Unit }
class C <: A & B {
public func a(): Unit { ... }
public func b(): Unit { ... }
}
接口也可以继承其他接口:
interface A { func a(): Unit }
interface B <: A { func b(): Unit }
// 实现B的类也需要实现A的方法
class C <: B {
public func a(): Unit { ... }
public func b(): Unit { ... }
}
三、属性(Property)
3.1 属性的基本概念
**属性(Properties)**提供了一个getter和一个可选的setter来间接获取和设置值。使用属性的时候与普通变量无异,但可以对内部实现进行封装,实现访问控制、数据监控等机制。
属性的基本语法:
class 类名 {
[修饰符] prop 属性名: 类型 {
get() { ... }
set(value) { ... }
}
}
3.2 属性的定义
一个简单的属性示例:
class Person {
private var _age: Int64 = 0
public mut prop age: Int64 {
get() {
println("Getting age")
return _age
}
set(value) {
println("Setting age")
_age = value
}
}
}
3.3 属性的分类
属性分为两类:
- 只读属性:只有getter,没有setter
- 可读写属性:既有getter也有setter
只读属性定义:
class Circle {
var radius: Float64
// 只读属性
public prop area: Float64 {
get() {
return 3.14 * radius * radius
}
}
}
可读写属性需要使用mut
修饰:
class Temperature {
private var _celsius: Float64 = 0.0
public mut prop celsius: Float64 {
get() { _celsius }
set(v) { _celsius = v }
}
public mut prop fahrenheit: Float64 {
get() { _celsius * 9/5 + 32 }
set(v) { _celsius = (v - 32) * 5/9 }
}
}
3.4 属性的使用场景
属性特别适合以下场景:
- 需要封装内部存储,对外提供统一访问接口
- 需要在获取或设置值时执行额外逻辑(如验证、通知等)
- 需要计算派生值
class BankAccount {
private var _balance: Int64 = 0
public mut prop balance: Int64 {
get() { _balance }
set(value) {
if value < 0 {
throw Exception("Balance cannot be negative")
}
_balance = value
}
}
// 只读计算属性
public prop isOverdrawn: Bool {
get() { _balance < 0 }
}
}
3.5 属性与字段的区别
虽然属性看起来像字段,但它们有重要区别:
- 属性是计算得到的,可以有复杂的获取和设置逻辑
- 属性可以只有getter(只读)或同时有getter和setter(可读写)
- 属性可以基于其他字段计算得到
class Person {
// 字段
private var firstName: String
private var lastName: String
// 计算属性
public prop fullName: String {
get() { "${firstName} ${lastName}" }
set(value) {
let parts = value.split(" ")
firstName = parts
lastName = parts
}
}
}
四、类、接口与属性的综合应用
4.1 使用接口定义契约
interface Shape {
prop area: Float64 { get }
func draw(): Unit
}
class Circle <: Shape {
var radius: Float64
public prop area: Float64 {
get() { 3.14 * radius * radius }
}
public func draw(): Unit {
println("Drawing circle with radius ${radius}")
}
}
class Rectangle <: Shape {
var width: Float64
var height: Float64
public prop area: Float64 {
get() { width * height }
}
public func draw(): Unit {
println("Drawing rectangle ${width}x${height}")
}
}
4.2 使用属性封装状态
class Thermostat {
private var _temperature: Float64 = 20.0
private var _mode: String = "cooling"
public mut prop temperature: Float64 {
get() { _temperature }
set(value) {
if value < 10 || value > 40 {
throw Exception("Temperature out of range")
}
_temperature = value
}
}
public mut prop mode: String {
get() { _mode }
set(value) {
if value != "cooling" && value != "heating" {
throw Exception("Invalid mode")
}
_mode = value
}
}
}
4.3 实现多态行为
interface Logger {
func log(message: String): Unit
}
class ConsoleLogger <: Logger {
public func log(message: String): Unit {
println("[Console] ${message}")
}
}
class FileLogger <: Logger {
var filePath: String
public func log(message: String): Unit {
// 实现文件写入逻辑
}
}
class App {
private var _logger: Logger
public init(logger: Logger) {
_logger = logger
}
public func run(): Unit {
_logger.log("Application started")
// 应用逻辑
}
}
五、最佳实践与注意事项
5.1 类的设计原则
- 单一职责原则:一个类应该只有一个引起它变化的原因
- 开闭原则:类应该对扩展开放,对修改关闭
- 依赖倒置原则:依赖抽象而不是具体实现
5.2 接口的设计建议
- 接口应该小而专注(ISP原则)
- 优先使用组合而不是继承
- 考虑为常用操作提供默认实现
5.3 属性的使用技巧
- 保持属性操作轻量级,复杂逻辑应放在方法中
- 考虑线程安全性,特别是在多线程环境中
- 避免在属性getter/setter中抛出异常
- 避免属性依赖其他可能为null的对象
5.4 常见陷阱
- 避免属性递归调用:
public mut prop value: Int64 {
get() { value } // 无限递归!
set(v) { value = v } // 无限递归!
}
- 注意值类型和引用类型的区别:
struct Point { var x, y: Int64 }
class Line { var start, end: Point }
var line = Line()
line.start.x = 10 // 这不会修改line的start,因为Point是值类型
- 谨慎使用可变属性,特别是在多线程环境中
六、总结
仓颉语言中的类、接口和属性构成了其面向对象编程的核心。类提供了对象的蓝图和实现,接口定义了类型之间的契约,而属性则提供了灵活的数据访问方式。通过合理使用这些特性,开发者可以构建出模块化、可扩展且易于维护的代码。
关键要点:
- 类是引用类型,支持继承和多态
- 接口定义抽象行为,一个类型可以实现多个接口
- 属性封装了状态访问,可以添加额外逻辑
- 组合优于继承,面向接口编程
- 遵循SOLID原则设计类和接口
通过掌握这些概念和技巧,开发者可以充分利用仓颉语言的面向对象特性,构建出高质量的软件系统。
更多推荐
所有评论(0)