面向对象架构中,能否将数组传入多个类?求最佳实践
面向对象架构优化方案建议
针对你遇到的上帝类、贫血领域模式及类命名问题,以下是贴合OOP最佳实践的优化思路:
1. 拆分职责:区分领域实体、集合类与服务类
- 领域实体类(名词):定义
Journey类,封装单个学习旅程的属性和自身专属行为,比如验证数据合法性的validate()、更新完成状态的markAsCompleted()、累加学习时长的addLearningHours()等,让实体拥有自主行为,避免沦为单纯的属性容器。 - 集合类(名词):保留
JourneyCollection但收缩职责,仅负责Journey对象的集合管理——比如添加/移除实体、基础的筛选排序,复杂逻辑可委托给专门类处理,不包揽所有业务。 - 服务类(名词):如果存在跨实体或非核心业务逻辑(比如批量导入、本地存储交互),单独创建
JourneyStorage、JourneyReportService这类服务类,专注单一功能。
2. 规避上帝类的具体操作
- 拆分原
JourneyCollection中的非集合逻辑:将数据持久化(如前端本地存储)交给JourneyStorage类;把复杂筛选规则拆成JourneySubjectFilter、JourneyCompletionFilter等专用过滤器,由JourneyCollection调用而非自行实现。 - 严格遵循单一职责原则:每个类只负责一件事,比如
JourneyCollection仅维护集合的完整性和基础操作,筛选排序的具体规则由过滤器类完成。
3. 避免贫血领域模式的关键
- 不让
Journey类只存属性:所有涉及单个旅程的状态变更、数据校验都封装在Journey内部,外部只能通过调用它的方法修改状态,比如用addLearningHours(5)替代直接修改journey.hours +=5,同时在方法内做合法性校验(如时长不能为负)。 - 集合类操作依赖实体方法:比如
JourneyCollection的addJourney()方法会先调用journey.validate(),确保数据合法后再加入集合,而非直接操作实体属性。
4. 类命名原则的重要性
- 类是对事物的抽象,用名词命名能清晰体现其代表的实体或服务,契合OOP封装数据与行为的核心思想。动词命名的类本质是函数的包装,违背了类的设计初衷,会让代码结构混乱、难以维护。
- 示例:用
JourneyCollection.addJourney(journey)替代单独的AddJourney类,或让JourneyService.createAndAddJourney(data)完成创建+添加的组合操作,语义更符合OOP逻辑。
示例代码片段
// 领域实体类:Journey class Journey { constructor(subject, startDate, hours = 0) { this.subject = subject; this.startDate = startDate; this.hours = hours; this.completed = false; } validate() { if (!this.subject || !this.startDate) throw new Error("必填字段缺失"); if (this.hours < 0) throw new Error("学习时长不能为负数"); } markAsCompleted() { this.completed = true; } addLearningHours(hours) { if (hours > 0) this.hours += hours; } } // 集合类:JourneyCollection class JourneyCollection { constructor() { this.journeys = []; } addJourney(journey) { journey.validate(); this.journeys.push(journey); } filterBySubject(subject) { return this.journeys.filter(j => j.subject === subject); } sortByStartDate(ascending = true) { return [...this.journeys].sort((a, b) => { const dateA = new Date(a.startDate); const dateB = new Date(b.startDate); return ascending ? dateA - dateB : dateB - dateA; }); } } // 服务类:JourneyStorage(负责本地存储) class JourneyStorage { saveCollection(collection) { localStorage.setItem('journeys', JSON.stringify(collection.journeys)); } loadCollection() { const data = localStorage.getItem('journeys'); const collection = new JourneyCollection(); if (data) { JSON.parse(data).forEach(item => { const journey = new Journey(item.subject, item.startDate, item.hours); journey.completed = item.completed; collection.addJourney(journey); }); } return collection; } }
内容的提问来源于stack exchange,提问作者Kevin Greetham
相关产品推荐
相关产品推荐

