Rust实现工厂模式时Terminal私有id字段无法被工厂赋值如何解决
解决方案
1. 用模块可见性控制构造权限(最简便)
Rust的可见性系统支持细粒度的访问限制,不需要friend关键字就能实现仅允许工厂访问构造函数的需求。你可以将Terminal和TerminalFactory放在同一模块下,给Terminal的构造函数设置模块级可见性,完全不会暴露给外部调用者:
mod terminal_core { #[derive(Debug)] pub struct Terminal { id: u32, pub name: String, } impl Terminal { // pub(crate) 仅当前 crate 可见,库的外部使用者完全无法调用 pub(crate) fn new(id: u32, name: String) -> Self { Self { id, name } } pub fn get_id(&self) -> u32 { self.id } } pub struct TerminalFactory { next_id: u32, } impl TerminalFactory { pub fn new() -> Self { Self { next_id: 1 } } pub fn create_terminal(&mut self, name: String) -> Terminal { let terminal = Terminal::new(self.next_id, name); self.next_id += 1; terminal } } } // 对外仅暴露两个公共类型,隐藏构造函数 pub use terminal_core::{Terminal, TerminalFactory};
如果需要更严格的限制,可以把pub(crate)替换为pub(super)(仅父模块可见)或者pub(in crate::path::to::factory)(精确限定仅工厂所在路径可见),权限控制粒度远高于friend关键字。
2. 构造令牌方案(跨模块场景更灵活)
如果后续重构需要把两个类型拆分到不同模块,可以用零成本的私有令牌做权限校验,外部没有令牌根本无法调用构造函数:
// 私有令牌类型,仅工厂所在模块可以生成 #[derive(Debug, Clone, Copy)] struct TerminalConstructToken; pub struct Terminal { id: u32, pub name: String, } impl Terminal { // 构造函数强制要求传入私有令牌 pub fn new(_token: TerminalConstructToken, id: u32, name: String) -> Self { Self { id, name } } pub fn get_id(&self) -> u32 { self.id } } pub struct TerminalFactory { next_id: u32, } impl TerminalFactory { pub fn new() -> Self { Self { next_id: 1 } } pub fn create_terminal(&mut self, name: String) -> Terminal { // 只有工厂能生成令牌完成构造 Terminal::new(TerminalConstructToken, self.next_id, name) } }
令牌是零大小类型,编译后会被完全优化,没有任何运行时开销。
关于设计模式与SOLID的说明
经典设计模式不需要硬套其他语言的实现逻辑,结合Rust的语言特性适配即可。你担心的非法实例问题Rust天然就能规避:只要Terminal存在私有字段,且没有对外暴露全参数构造函数,外部代码完全无法手动初始化Terminal实例,不可能出现非法的id值。
Rust的组合优先、trait接口隔离、所有权规则本身就非常贴合SOLID原则的核心要求,中等规模项目完全可以落地,不需要照搬OOP语言的实现套路。
内容的提问来源于stack exchange,提问作者pid
相关产品推荐
相关产品推荐

