开发中对象定名的一点思考

打印 上一主题 下一主题

主题 860|帖子 860|积分 2580

引言

在我所见过的项目中,大多数团队都倾向于“功能堆砌式”开发:需求来了就加逻辑或函数,却很少有人乐意花时间在计划上,尤其是在对象定名花费时间。这看似“快速实现需求”的方式,通常会对代码的可读性产生坏的影响,进而影响可维护性。
一个好的对象定名并非只是让代码表面看起来整齐;它背后关系到人类和 AI 对系统的认知方式,也会在后续维护和迭代中形塑程序员以及 AI 工具的行为。换句话说,符合的定名不但决定了当前代码的优雅水平,也会潜移默化地影响未来对代码进行修改、扩展和重构时的思维路径与决策过程。
下面,我们将通过几个示例,探讨如何通过公道的定名让对象真正体现业务含义与自主决策能力,而不是简朴地饰演一个“被动执行者”。
 
一、避免以er或or结尾的对象定名

想象你走进一家餐厅。你会如何点餐?是要一份宫保鸡丁,还是告诉厨师:“你先放油,然后大火爆炒,然后再加调料”?如果你选择后者,那么对应到程序计划中,大概就是下面的写法:
  1. class FoodMaker {
  2.     public Dish Cook(List<Step> cookingSteps) {
  3.         foreach(var step in cookingSteps) {
  4.             ExecuteStep(step);
  5.         }
  6.         return new Dish();
  7.     }
  8. }
  9. // 客户端代码
  10. var maker = new FoodMaker();
  11. var steps = new List<Step> {
  12.     new Step("放油"),
  13.     new Step("大火爆炒"),
  14.     new Step("加调料")
  15. };
  16. var dish = maker.Cook(steps);
复制代码
FoodMaker ,它只是一个“做饭的人”或“执行器”,缺乏更多的“主观能动性”。这不但增长了使用者在思维层面的负担,也显得对专业厨师的经验和技能不够尊重。
相比之下,更贴近现实的方式是直接告诉对方“我需要一份宫保鸡丁”,厨师会根据自身经验和对食材的理解来完成这道菜。例如:
  1. Chef {
  2.     public Dish PrepareKungPaoChicken() {
  3.         // 厨师知道如何准备这道菜
  4.         return new KungPaoChicken();
  5.     }
  6. }
  7. // 客户端代码
  8. var chef = new Chef();
  9. var dish = chef.PrepareKungPaoChicken();
复制代码
 
这样,Chef 完整体现了专业性与自主性:

  • 脚色名称直接让人遐想到一个可自主决策、拥有专业技能的人,而非简朴的“烹调器”。
  • 客户端只需表达“想要什么菜品”,而不必详述所有步骤。
  • 厨师可以根据具体的食材和场景调整做菜细节,为业务带来更多灵活性。
值得留意的是,很多以 “-er” 或 “-or” 结尾的对象(如 Manager、Processor、Controller、Validator 等)经常会出现出类似的“过程化”倾向:它们更多体现的是过程集合而非业务主体。当我们把定名改为更能传达专业身份或业务脚色的名词时,往往会看到对象的“自我意识”和“主观能动性”随之提升,从而让整个系统的抽象层次更高、可维护性更好。
 
二、“Service”“Helper”“Utility”等后缀,更容易出现“上帝类”

在 AI 辅助编程工具的遍及下,定名的清楚度在大型项目中显得尤为重要。模糊或过于抽象的名字不但会增长团队成员、以致让3个月后的你自己的认知负担,也会让 AI 在大量上下文中难以理解该对象的真实意图,以致产生误导性补全。我们先来看一个不恰当的示例:
错误示例:RestaurantService 集合了一切琐事
  1. public class RestaurantService {
  2.     // 名称看似管理餐厅的一切,却混合了做饭、送餐和财务等完全不同的功能
  3.     // 烹饪某道菜
  4.     public void cookDish(String dishName) {
  5.         
  6.     }
  7.     // 将菜品送到指定地址
  8.     public void deliverFood(String address) {
  9.         
  10.     }
  11.     // 安排厨师、服务员等员工的工作排班
  12.     public void scheduleStaff(String staffName, String shift) {
  13.         
  14.     }
  15.     // 处理餐厅每天或每月的财务结算
  16.     public void handleBilling() {
  17.         
  18.     }
  19. }
复制代码
问题:


  • 过于宽泛、抽象的类名:RestaurantService 似乎负责所有与餐厅相干的功能,从做菜到送餐再到财务结算,远远超出了单一职责的范围。
  • 对 AI 的误导:当 AI 工具在大规模代码库中搜刮或补全时,见到“RestaurantService”可能以为这里面能找到任何与餐厅运营相干的逻辑,补全时也可能把更多不相干的功能(例如“采购食材”、“营销活动”等)一股脑塞进来,很容易导致上帝类。
  • 难以维护与扩展:如果将来要更改配送方式或财务记账逻辑,你会发现所有功能都耦合在同一个类里,一次改动极有可能波及整个系统。
 
更公道的计划:按专业分工拆分类

要让代码更易读、更具可维护性,也让 AI 分析更正确,我们可以将“餐厅运营”按照现实场景拆分成多个专门对象,让每个类名更能“自证其职”:
  1. // 专注做菜逻辑
  2. public class Kitchen {
  3.     public void cookDish(String dishName) {
  4.         // 专业处理做菜流程
  5.     }
  6. }
  7. // 专注外卖配送
  8. public class Delivery {
  9.     public void deliverFood(String address) {
  10.         // 专业处理送餐流程
  11.     }
  12. }
  13. // 专注人员排班
  14. public class StaffScheduling {
  15.     public void schedule(String staffName, String shift) {
  16.         // 专业处理员工排班
  17.     }
  18. }
  19. // 专注财务结算
  20. public class Billing {
  21.     public void settleAccounts() {
  22.         // 专门处理账务结算
  23.     }
  24. }
复制代码
好处:


  • 职责明确:Kitchen 只做烹调,Delivery 只管外卖,StaffScheduling 只负责排班,Billing 用于结算财务。每个对象都有清楚的专业范畴。
  • 易于理解:无论是人还是 AI,看到类名便能迅速推断其功能,低落误解。
  • 便于扩展:将来需要为“配送”加入自动调理,或为“做菜”加入菜单保举逻辑,也可以在对应的类中单独迭代,而不会影响其他模块。
  • 匹配现实场景:现实中,餐厅的后厨、配送员、人事、财务等各司其职,软件计划中也应遵循类似原则。
 
三、对象定名与对象“智能”属性:当环境变化时仍能自适应

现实生活中,若宫保鸡丁的必需食材(例如花生)忽然缺货,真正的专业厨师会自动探求替代食材,而不会要求顾客重新“下指令”或“换个点餐方式”。同理,在软件中,一个计划得足够“智能”的对象,也应该能在外部条件或业务需求变化时,自行调整内部逻辑,而不影响调用者的使用方式。
 
示例:面相过程的烹调
  1. public class CookingProcess {
  2.     public Dish cook(String dishName) {
  3.         // 无论食材是否缺货,都执行固定步骤
  4.         // ...
  5.         return new Dish(dishName); // 返回做好的菜
  6.     }
  7. }
复制代码
局限:

  • 一旦食材缺货,需要调用方自己判定是否可做这道菜,或修改烹调流程。
  • 每次需求变化,都得改动 cook 方法或调用代码,无法实现真正的“自适应”。
 
改进示例:厨师是专业人士,能适配环境变化

下面的 Chef 内部自行决定花生是否可用,如果缺货就用其他食材替代。这样,纵然后续有更多类似变化(换新调料、临时供应商等),也能集中在 Chef 内部调整,无需改动客户端调用代码。
  1. public class Chef {
  2.     // 模拟花生库存状态,可来自数据库或配置文件
  3.     private boolean peanutsInStock = false;
  4.     public Dish prepareDish(String dishName) {
  5.         if ("宫保鸡丁".equals(dishName)) {
  6.             // 如果花生缺货,就用其他干果替代
  7.             if (!peanutsInStock) {
  8.                 // ...在内部改用腰果或其他替代食材
  9.             }
  10.             // ...否则正常使用花生
  11.         }
  12.         // 其余烹饪逻辑
  13.         return new Dish(dishName);
  14.     }
  15. }
复制代码
好处:

  • 内聚性强:所有判定和替代逻辑都放在 Chef 内部,外界无需关心具体做法。
  • 客户端调用稳固:无论花生库存状态如何变化,调用者依旧只需“一句下令”点餐,即可得到结果。
  • 可扩展:将来若再碰到更多类似场景(例如某调料临时售罄),只需修改 Chef,不会影响已有的调用代码。
  •  
客户端调用示例:环境/需求变化,不影响客户端调用
  1. public class Main {
  2.     public static void main(String[] args) {
  3.         Chef chef = new Chef();
  4.         // 客户端只需告诉厨师要做“宫保鸡丁”
  5.         Dish dish = chef.prepareDish("宫保鸡丁");
  6.         // 即使花生缺货,Chef 会自动使用其他食材,无需调用方改动
  7.     }
  8. }
复制代码
无论花生库存如何,客户端调用方式始终一致:一个智能的 Chef 能在内部完成相应的“自适应”处理。
 
小结:定名即计划,把对象当做有生命的实体并可以或许自主决策行为

对象的定名,许多人往往只把它当作“好看”或“顺口”的问题,却忽视了它所暗含的业务理解深度与系统思维。当我们刻意避开 “-er” 结尾或“Service”、“utility”后缀等含糊标签,并让对象名真实反映其专业脚色与业务职责时,可以或许有下述好处:

  • 减少误解
    新成员或 AI 工具都能迅速理解类的意图,防止在补全或分析时走偏。
  • 提升内聚
    各对象的逻辑边界更加清楚,改变一处功能不必连带修改全局。
  • 易于扩展
    每个对象如同灵活的模块,可独立维护、替换或升级,而不影响整体架构。
  • 贴近业务
    与产物或业务团队在概念层面保持一致,沟通效率提升,也减少了架构计划与业务需求间的鸿沟。
 
在软件工程中,定名的重要性通常被忽视,但定名自己潜移默化影响我们的编码时的思维。只有当我们真正将对象视为拥有“尊严”与“自主决策能力”的实体时,才能更容易构建出一个高内聚、易扩展、符合业务本质的系统。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

宝塔山

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表