面向对象的思维方法
从学 Java 才真正碰到 OOP。习惯用 C 的人,往往会嫌 Java 慢、代码长、一件小事要拆好多类。抵触很正常;真正别扭的,是不知道该怎么提炼类,一不小心又滑回过程式思路。
面向对象的精髓,是从现实世界的人类思维习惯出发:先谈业务要什么,再翻译成程序能懂的结构。封装的是业务逻辑,不是 select 语句。
| 思路 | 怎么切 | 问题 |
|---|---|---|
| 自底向上(机器视角) | 按读库、编码、解析参数拆模块 | 类跟着实现细节走,换 C 写两个函数更清楚 |
| 自上而下(业务视角) | 先有计数器、邮件这些“东西”和它们会做的事 | 过早想 JDBC / Vector,又会掉回实现驱动 |
一、发广告邮件:别按程序员的手拆类
邮件列表在数据库里。用 C 会想:读邮件内容 → 连库循环取地址 → 调本机 qmail 的 sendmail。改用 Java 后,怕全塞进 main,于是拆三个类:一个读库并发送,一个读内容做 MIME,一个主类解析命令行。这是按实现步骤自底向上切的,设计时已经把底层细节想完了。
从业务看,一封邮件有头、体、地址;要能发送,还要能列出所有地址。类应该是 JunkMail,而不是“读库类 / 编码类 / 参数类”。
(原文构造方法误写成 JunkMain,这里按类名改回 JunkMail。)类设计好了,调用发送会轻松很多。qmail、JDBC 是方法体里的事,不是类的切分依据。
二、网页计数器:从需求倒推接口
访问 http://hostname/count.cgi?id=xxx,后台表里每个 id 对应一个计数值(这里忽略并发锁表)。过程式会想:从 HTTP GET 取 id → 查表 → 加 1 → 更新 → 显示。
没有编程经验的人会说:我要一个计数器,刷新页面加 1,最好能清 0,再能设成任意值就可以“作弊”。他不会先想数据库和 HTTP 变量。按这个习惯,需要一个 Counter 类:
框架先有了,getCount() 里再去访问数据库。学习 JDBC 时最容易问错的是:“我怎样封装对数据库的 select?”——设计阶段封装的是业务,读库是编码实现阶段的事。
三、用户列表:返回接口而不是 Vector
Web 里常要分页列出所有用户。User 有 addUser、deleteUser、listUsers。增删对应 insert / delete 很好办;listUsers 本质是 select 出一个记录集。方法只能有一个返回值,于是很多人返回 Vector,在方法里把记录一条条塞进去。主程序再遍历 Vector。
这样已经能用,但设计时就绑死了 Java 的集合类,违反“设计阶段不过早考虑具体语言实现”。对集合遍历,抽象成 hasNext / next 更稳:
任何实现了 next / hasNext 的类都能表达“用户列表”,不必绑死 Vector;ArrayList 可以,自己写一个类也可以。耦合度下来,实现阶段才有最大灵活性。JunkMail 的 listAllMail() 同样应该改成接口类型。
四、自上而下,先主后次
过程式符合机器跑指令的流程;面向对象符合人解决问题的过程:先把主要矛盾收成简单框架,再把细节拆成小问题。设计时心里常担心“不考虑代码,怎么知道类一定能实现”,于是每设计一个接口都用熟悉的语言默默评估一遍——一不小心又回到按程序功能切类。
抓住这一点,设计和编码会不那么枯燥;合理运用面向对象的软件,会带一点思维上的干净。软件只是载体,业务才是目标。
一句话总结:先按人类业务习惯抽象类和接口,再在方法体里写 JDBC 和集合;切类按“有什么、能干什么”,不要按“先读库再发信”的实现步骤。
转载请注明来源:面向对象的思维方法







