仓颉语言包示例:演示包结构和访问修饰符的使用
本文通过仓颉语言示例展示了包结构和访问修饰符的使用。示例包含demo8主包及其子包business和two,演示了public、internal、protected和private四种访问修饰符的控制效果。其中PaymentProcessor类作为基类,其子类CreditProcessor展示了继承关系中访问权限的控制,而ExternalService则验证了跨包访问的边界限制。主程序main.cj整合调用各模块功能,体现了仓颉语言的模块化设计、封装性和面向对象特性。示例重点验证了protected与public的区别,以及跨模块访问时修饰符的控制作用,展示了仓颉语言在代码组织和访问控制方面的核心能力。
顺便提示,如何在CodeArts IDE for Cangjie 创建的工程(Project) 源码根目录src上新建源码文件或子目录(子包)?
右击src可见相关快捷菜单命令项。
仓颉编程语言中的包的基础知识可见 https://blog.csdn.net/cnds123/article/details/149782471
包结构如下:
demo8
│
src/
├── main.cj // 入口
├── business/ // business包
│ ├── finance.cj // business包的finance.cj
│ └── utils.cj // business包的utils.cj
└── two/ // two包
└── other.cj // two包的other.cj
1.business/utils.cj 的源码:
package demo8.business
//注意,声明为public 和open 才能被其他包访问
public open class PaymentProcessor {
private var transactionId: Int64 = 0
internal var merchant = "Default"
protected var feeRate: Float64 = 0.03
public var currency = "USD"
public PaymentProcessor() {}
public init(currency: String) {
this.currency = currency
}
}
internal class SecurityUtils {
public func encrypt(data: String): String {
return "ENCRYPTED:${data}"
}
}
2. business/finance.cj 的源码:
package demo8.business
// 声明为 public
public class CreditProcessor <: PaymentProcessor {
// public init() {
// super()
// }
// 整数版本
public func process(amount: Int64) {
process(Float64(amount))
}
// 浮点数版本
public func process(amount: Float64) {
let fee = amount * feeRate
println("收取 ${fee} ${currency}")
merchant = "CreditCo"
let utils = SecurityUtils()
println(utils.encrypt("敏感数据"))
}
}
3.two/lib.cj 的源码:
package demo8.two
import demo8.business.PaymentProcessor // 跨包导入business包的类PaymentProcessor
public class ExternalService {
public func demo() {
let processor = PaymentProcessor()
processor.currency = "JPY" // 修改为日元测试
println("== 跨包访问测试 ==")
println("设置货币: ${processor.currency}")
// 以下尝试会编译失败(取消注释测试)
// processor.merchant = "Tokyo" // ✗ internal不可访问
}
}
4. 入口主程序 (main.cj)源码
package demo8
import demo8.business.PaymentProcessor // 导入business包的类PaymentProcessor
import demo8.business.CreditProcessor // 导入business包的类 CreditProcessor
import demo8.two.ExternalService // 导入two包的类ExternalService
main() {
let base = PaymentProcessor() // 创建对象
let credit = CreditProcessor() // 创建对象
// 测试整数调用
println("整数付款测试:")
credit.process(100)
// 测试浮点数调用
println("\n浮点数付款测试:")
credit.process(99.99)
// 测试货币设置
println("\n货币设置测试:")
let euroProcessor = PaymentProcessor("EUR") // 创建对象
println("新货币: ${euroProcessor.currency}")
// 调用跨包服务
println("\n调用外部服务:")
ExternalService().demo() // 这句和下面两句等价
// let tempObj = ExternalService()
// tempObj.demo()
}
编译运行请跨部分
运行输出:
整数付款测试:
收取 3.000000 USD
ENCRYPTED:敏感数据
浮点数付款测试:
收取 2.999700 USD
ENCRYPTED:敏感数据
货币设置测试:
新货币: EUR
调用外部服务:
== 跨包访问测试 ==
设置货币: JPY
分析说明提要:
这个工程完美展示了仓颉语言的三大核心能力:
模块化:通过包实现代码组织
封装性:精细的访问控制(private/internal/protected/public)
面向对象:类继承、方法重载、多态
整个工程以 demo8 为主包,通过子包划分功能模块,符合模块化设计原则:
• 主入口:src/main.cj 作为程序入口,负责统筹调用各模块功能。
• 业务核心包:src/business/ 封装支付相关的核心逻辑,包含:
utils.cj:定义基础类(PaymentProcessor)和包内工具类(SecurityUtils)。
finance.cj:实现具体支付方式(CreditProcessor,继承自 PaymentProcessor)。
• 外部服务包:src/two/ 模拟跨包调用场景(ExternalService),用于验证跨包访问规则。请留意other.cj其中有跨包导入。
代码文件要点说明
finance.cj中的CreditProcessor 类成功访问了 utils.cj 中的父类PaymentProcessor的 protected 和 internal 成员,完成费用计算和商户名称修改。
utils.cj中的类SecurityUtils 在同包内正常使用,完成数据加密。
other.cj中跨包的类 ExternalService 只能修改 public 的 currency,无法触碰 internal 成员。
主程序main.cj通过导入不同包的类,串联起所有功能,体现了模块化协作的有效性。
访问修饰符的核心作用与验证
仓颉语言的 4 种访问修饰符(private、internal、protected、public)在示例中被充分验证。
控制成员的可见性,共 4 种
修饰符 可见范围
private 仅当前类内部
internal 当前包及子包(默认)
protected 当前模块及当前类的子类
public 模块内外均可见
【在仓颉(Cangjie)语言里,包(package) 与 模块(module) 的对应关系可以一句话总结为:
一个模块 = 一个 cjpm (Cangjie Package Manager:仓颉包管理器)项目 = 一个仓颉独立的构建和分发单元。
包(package)只是模块内部的“命名空间”层级,用来组织源码目录。】
protected 和 public 的区别
protected
• 不仅是“能访问”,还隐含“可继承”——子类可以覆写该成员。
• 同时受“模块”限制:别的模块即使继承了该类,也看不见 protected 成员;
• 只有同一个模块内的子类才能继承/覆写。
public
• 只是“能看见”,不隐含可继承;
• 任何模块都能看见,但覆写仍需要 open + override。
• 没有模块边界限制,跨模块也能用。
【在仓颉里,“跨模块”就是跨 cjpm 项目。
你可以把 A 项目编译成 .cjpm(库),然后在 B 项目里把它声明成依赖,就能“跨模块”使用。】
类继承与访问权限的配合
示例中 CreditProcessor <: PaymentProcessor 的继承关系,进一步验证了访问修饰符在继承场景的作用:
1.继承前提:PaymentProcessor 必须声明为 open 才能被继承(仓颉中类默认不可继承,需显式 open),且为 public 才能被跨包继承。
2.子类访问父类成员:CreditProcessor 作为子类,可访问父类的 protected(feeRate)、internal(merchant)、public(currency)成员,但无法访问 private(transactionId),符合权限规则。
3.方法重载:CreditProcessor 重载了 process 方法(整数 / 浮点数版本),均声明为 public,确保外部可调用。
跨包调用的边界控制
two/other.cj的 ExternalService 模拟了跨包访问场景,清晰展示了包间访问的边界:
• 允许访问:PaymentProcessor类 的 public 成员(如 currency)和构造函数。
• 禁止访问:PaymentProcessor 类的 internal 成员(如 merchant,注释代码编译失败),体现了 “包内私有” 的隔离性。