对象命名怎么上手?从现实世界

  之前的一篇文章提到过关于对象的命名,核心观点是:命名应反映业务角色与专业性,以提升代码的可读性、内聚性与可扩展性,最终提升可维护性。

  而可维护性是软件的系统的核心。

  但理解这个概念可能需要一些背景知识和时间,那么如何快速上手?本篇文章对这些概念进行简单的阐述,并通过一个案例说明命名的进步过程。

 

核心领域与非核心领域的命名差异

  对象命名首先需要区分我们在命名什么,对象所处的位置是核心领域(Core Domain)还是非核心领域(Non-Core Domain)。

      • 核心领域 是指承载业务本质的关键部分,直接反映系统的核心价值。例如,在学校管理系统中,“课程表(CourseSchedule)”是核心领域,负责协调课程、教师和教室资源;在电商系统中,“订单(Order)”则是核心领域,涵盖商品购买的生命周期。核心领域的命名应高度贴近业务术语,体现专业性与角色职责。
      • 非核心领域 则是支持性的技术性模块,如日志记录(Logging)、数据访问(DataAccess)。这些部分的命名可以适当使用技术性后缀(如“Manager”“Repository”),以突出其辅助角色。

 

为何区分? 因为核心领域的命名直接影响业务逻辑的清晰度和系统的可维护性,而非核心领域更注重技术实现的通用性。例如,“CourseSchedule”比“ScheduleManager”更能直观表达课程安排的业务角色,而“LogManager”则适合非核心的日志功能。如果对应到DDD,这两部分通常被划分为核心域与支持域。

为什么核心域需要更贴近业务?核心域是业务的核心竞争力所在,需要高度的定制化和精确性。因此,应该避免使用过于通用的命名,以免掩盖业务的独特性。

 

命名尽量贴近领域,贴近现实世界

开头我们首先区分了核心领域与非核心领域,下面我们说的规则主要应用与核心领域。

对于核心领域,命名需要更多从现实世界中获取,这是因为现实世界的概念已经过长期发展和演化: 现实世界中的角色、领域概念,例如“顾客”、“订单”、“银行账户”、“医生”、“病人”等等, 并非凭空捏造,而是经过漫长的社会实践、商业活动、科学研究等发展而来。它们在实践中不断被验证、修正和完善,其边界、责任和功能通常已经非常清晰和成熟。

同时,现实世界中的对象由于较为常见,日常生活中已经理解这些对象的概念与意义,不再需要在软件中增加额外的负载(还记得上学时做英语阅读理解,如果主题和日常相关,很多单词不认识也能大概猜出文章意思,如果文章太抽象,提到的内容不在日常生活内,即使每个单词都认识,还是难以理解文章概念?)

下面是一个简单Demo说明,一个学校排课系统,通过合理的命名,能够延伸出显性和隐性的职责。

/**
 * 代表学校教学安排的领域对象
 * 核心职责是管理课程安排与资源协调
 */
public class CourseSchedule {
    // 核心职责(显性)
    private Map<TimeSlot, Classroom> assignedRooms;

    public void assignTeacher(Course course, Teacher teacher) {
        /* 分配授课教师并验证资质 */
    }

    // 核心职责(显性)
    public boolean checkTimeConflict(LocalDateTime newSlot) {
        /* 检查新时段是否与现有课程冲突 */
    }

    // 不应有的职责:
    // 1. 不处理学生考勤(属于AttendanceSystem)
    // 2. 不计算教师薪资(属于PayrollSystem)
    // 3. 不管理教学设备(属于TeachingEquipmentResource)

    // 隐含职责(后续扩展)
    public void generateIcalFeed() {
        /* 
         * 新增需求:生成日历订阅链接
         * 虽未在类名中体现,但现实中课程表天然需要时间同步功能
         * 添加此方法符合对象职责的自然延伸
         */
    }
}

 

 

 

不熟悉领域

上面的CourseSchedule表类虽然日常生活中容易理解,但也有一定的领域知识,如果我们一开始对领域并不熟悉,该怎么办?例如,“CourseSchedule”涉及学校管理的专业知识,作为开发者一开始比较懵逼,该怎么办?

 

从现实角色入手

通常来说,开发某个领域的代码,都可以先简单了解该领域的基础知识与词汇,当然有条件最好能与这个行业有经验的人沟通,也就是所谓的领域专家,比如CourseSchedule这个例子,可以提取名词--关键实体(如“课程”“教室”)和动词(如“安排”“冲突检查”),逐步构建命名。

 

避免缺乏灵魂的技术后缀

如果一开始想不好名字,那么可以先尽可能避免使用“er”“or”等模糊后缀,如“Scheduler”“Processor”,这些命名缺乏领域语义,难以反映业务角色,这可能导致丢失业务的精确度与定制性。但是本身已成为领域实体的词汇除外,例如“Teacher”。

 

渐进式演化

最开始如果并没有想到比较好的名字,可以从简单开始随着开发的进行,学习到新的领域,逐步演进,依然是CourseSchedule这个例子:

 

第1阶段 - ClassData(纯数据容器)

在这一阶段,命名仅关注数据的存储,缺乏业务语义的表达。ClassData作为一个纯数据容器,虽然简单易懂,但其局限性在于没有体现课程安排的业务角色,仅停留在技术层面的数据收集,职责边界模糊,无法反映现实世界的逻辑。

/**
 * 简单的课程数据类
 */
public class ClassData {
    private List<String> classes;
    private List<String> teachers;
    private List<String> rooms;
    
    public void addClass(String className, String teacher, String room) {
        /* 简单添加数据 */
    }
}

 

第2阶段 - ClassSchedule(引入业务概念)

相比ClassData,ClassSchedule迈出了关键一步,开始引入业务概念,命名从单纯的数据容器转向课程安排的初步表达。进步在于通过teacherAssignments和roomAssignments映射了教师和教室的分配关系,增加了简单的业务逻辑(如时间可用性检查)。然而,其局限性依然明显:命名仍偏技术化,未能完全贴近现实世界的“课程表”概念,职责定义较为粗浅,缺乏对领域规则的深入体现。

 

/**
 * 课程安排类
 */
public class ClassSchedule {
    private Map<String, String> teacherAssignments;  // 教师分配
    private Map<String, String> roomAssignments;     // 教室分配
    
    public void assignClass(String time, String teacher, String room) {
        /* 基础的课程安排逻辑 */
    }
    
    public boolean isTimeAvailable(String time) {
        /* 简单的时间检查 */
    }
}

 

第3阶段 -CourseScheduleManager(领域职责初具雏形)

相比ClassSchedule,CourseScheduleManager在业务表达上更进一步,通过引入Course和Teacher等领域实体,命名开始贴近学校管理的现实逻辑。进步体现在职责的细化,如教师分配加入了业务规则,时间冲突检查也更具体,体现了领域知识的深化。然而,其局限性在于“Manager”后缀仍带有技术化色彩,未能完全摆脱抽象管理的意味,可能模糊了“课程表”作为核心业务角色的直观性,限制了命名的语义精度。

/**
 * 课程表管理类
 */
public class CourseScheduleManager {
    private Map<TimeSlot, Classroom> roomAssignments;
    private Map<Course, Teacher> teacherAssignments;
    
    public void assignTeacher(Course course, Teacher teacher) {
        /* 增加了教师分配的业务规则 */
    }
    
    public boolean checkScheduleConflict(TimeSlot slot) {
        /* 增加了时间冲突检查 */
    }
}
最终阶段 - CourseSchedule(完整领域对象)

相比CourseScheduleManager,CourseSchedule完成了从技术视角到领域视角的转型,彻底贴近现实世界的“课程表”概念。进步在于去除了“Manager”后缀,直接以业务角色命名,职责边界更清晰,方法如generateIcalFeed自然延伸了课程表的时间属性,展现出可扩展性。此时已无明显局限性,命名与业务本质高度契合,直观&专业。

/**
 * 代表学校教学安排的领域对象
 * 核心职责是管理课程安排与资源协调
 */
public class CourseSchedule {
    private Map<TimeSlot, Classroom> assignedRooms;
    
    public void assignTeacher(Course course, Teacher teacher) {
        /* 分配授课教师并验证资质 */
    }
    
    public boolean checkTimeConflict(LocalDateTime newSlot) {
        /* 检查新时段是否与现有课程冲突 */
    }
    
    public void generateIcalFeed() {
        /* 生成日历订阅链接 */
    }
}

 

小结

命名是软件设计中看似微小却至关重要的环节,命名不仅仅是简单的代码问题,还是我们对业务本质理解水平的呈现,更是业务逻辑与领域专家沟通的关键。通过区分核心领域与非核心领域,我们明确了命名应优先服务于业务本质,尤其在核心领域中,贴近现实世界的概念能带来语义清晰、职责明确和可维护性提升。

 

 

 

 

原创作者: CareySon 转载于: https://www.cnblogs.com/CareySon/p/18741374
《餐馆点餐管理系统——基于Java和MySQL的课程设计解析》 在信息技术日益发达的今天,餐饮行业的数字化管理已经成为一种趋势。本次课程设计的主题是“餐馆点餐管理系统”,它结合了编程语言Java和数据库管理系统MySQL,旨在帮助初学者理解如何构建一个实际的、具有基本功能的餐饮管理软件。下面,我们将深入探讨这个系统的实现细节及其所涉及的关键知识点。 我们要关注的是数据库设计。在“res_db.sql”文件中,我们可以看到数据库的结构,可能包括菜品表、订单表、顾客信息表等。在MySQL中,我们需要创建这些表格并定义相应的字段,如菜品ID、名称、价格、库存等。此外,还要设置主键、外键来保证数据的一致性和完整性。例如,菜品ID作为主键,确保每个菜品的唯一性;订单表中的顾客ID和菜品ID则作为外键,与顾客信息表和菜品表关联,形成数据间的联系。 接下来,我们来看Java部分。在这个系统中,Java主要负责前端界面的展示和后端逻辑的处理。使用Java Swing或JavaFX库可以创建用户友好的图形用户界面(GUI),让顾客能够方便地浏览菜单、下单。同时,Java还负责与MySQL数据库进行交互,通过JDBC(Java Database Connectivity)API实现数据的增删查改操作。在程序中,我们需要编写SQL语句,比如INSERT用于添加新的菜品信息,SELECT用于查询所有菜品,UPDATE用于更新菜品的价格,DELETE用于删除不再提供的菜品。 在系统设计中,我们还需要考虑一些关键功能的实现。例如,“新增菜品和价格”的功能,需要用户输入菜品信息,然后通过Java程序将这些信息存储到数据库中。在显示所有菜品的功能上,程序需要从数据库获取所有菜品数据,然后在界面上动态生成列表或者表格展示。同时,为了提高用户体验,可能还需要实现搜索和排序功能,允许用户根据菜品名称或价格进行筛选。 另外,安全性也是系统设计的重要一环。在连接数据库时,要避免SQL注入攻击,可以通过预编译的PreparedStatement对象来执行SQL命令。对于用户输入的数据,需要进行验证和过滤,防止非法字符和异常值。 这个“餐馆点餐管理系统”项目涵盖了Java编程、数据库设计与管理、用户界面设计等多个方面,是一个很好的学习实践平台。通过这个项目,初学者不仅可以提升编程技能,还能对数据库管理和软件工程有更深入的理解。在实际开发过程中,还会遇到调试、测试、优化等挑战,这些都是成长为专业开发者不可或缺的经验积累
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值