面向对象入门到进阶:类与对象、封装与建模的工程化方法
大约 4 分钟
面向对象入门到进阶:类与对象、封装与建模的工程化方法
新手先看 · 一屏速览
- 类是“蓝图”,对象是“实例”;封装让变化在类内,稳定在类外
- 组合优先于继承:复用更安全、耦合更低;继承用在“明确 is-a”场景
- 值对象不可变,实体有身份;边界清晰、语义自洽,代码才好维护
1. 类与对象:从数据到行为的绑定
- 类 = 状态(字段)+ 行为(方法)+ 不变式(类内约束)
- 对象 = 类的实例,承载实际数据与运行时行为
示例:值对象建模
import java.util.Objects;
public final class Email {
private final String value;
private Email(String v){ this.value = v; }
public static Email of(String v){
if (v == null || !v.matches("^[\\w.-]+@[\\w.-]+$")) throw new IllegalArgumentException("bad email");
return new Email(v);
}
public String value(){ return value; }
@Override public boolean equals(Object o){ return o instanceof Email e && Objects.equals(value,e.value); }
@Override public int hashCode(){ return Objects.hash(value); }
@Override public String toString(){ return value; }
}- 不可变对象优点:线程安全、可缓存、作为 Map/Set 键更可靠
2. 封装与不变式:把变化关在门内
- 封装 = 对外暴露稳定 API,对内隐藏实现细节
- 不变式示例:金额不得为负、邮箱格式必须合法
- 防御式拷贝与只读视图:避免外部修改内部集合
3. 组合优先于继承:从“has-a”出发
class Engine { void start(){} }
class Car { private final Engine engine = new Engine(); void start(){ engine.start(); } }- 组合的优势:边界稳定、易测试;继承易破坏封装,引入“脆弱基类问题”
- 何时继承:明确的 is-a 且行为层面可替换;否则优先组合
4. UML 基础与读图
- 类图:类、接口、实现、关联、聚合、组合、依赖
- 关系强弱:依赖 < 关联 < 聚合 < 组合;箭头与菱形语义
- 用法:在设计评审与跨团队沟通时,辅助表达结构与依赖方向
5. 领域建模:实体与值对象
最近建一些几十个工作内推群,各大城市都有,群里目前已经收集了很多内推岗位,大厂、中厂、小厂、外包都有。 欢迎HR、开发、测试、运维和产品加入。

扫描下方微信,备注:网站+所在城市,即可拉你进工作内推群。

- 实体(Entity):有稳定身份标识(id),等价性按身份判断
- 值对象(Value Object):按值等价,不可变,常用于金额、邮箱、坐标等
- 服务(Domain Service):不适合挂到某个对象上的行为,抽成领域服务
示例:订单中的 Email、Money 建模(片段)
public final class Money { /* 参考 03/05 篇中不可变实现 */ }
public final class OrderId { /* 值对象,封装 id 表示 */ }
public final class Order {
private final OrderId id;
private final Email userEmail;
private Money total;
public Order(OrderId id, Email email){ this.id=id; this.userEmail=email; this.total=Money.of("0.00"); }
public void add(Money m){ this.total = this.total.add(m); }
}6. 不可变 vs 可变:工程取舍
- 不可变:更安全、可缓存、适合并发;但需要新对象创建(注意性能与内存)
- 可变:在热路径或批量构建场景常用;通过约束与封装控制副作用
- 经验:外部接口参数和返回优先不可变,内部构建阶段可变
7. 实战清单与反模式
- 清单:值对象封装关键概念;集合对外暴露只读视图;组合优于继承;API 语义清晰
- 反模式:贫血模型(所有逻辑都在 Service);臃肿类(上百字段与方法);误用继承复用
8. 练习与思考题
- 为“手机号、地址、金额”建值对象,保证不可变与合法性
- 将某个“继承复用”的类改为“组合复用”,分析测试与扩展性变化
- 画一张系统核心类图,标注组合/聚合/依赖,并描述为何如此划分
参考思路(节选)
- 值对象:构造时校验;equals/hashCode/toString 完整;作为 Map 键时语义正确
- 组合复用:将可变点提取为组件接口,核心类通过组合注入实现
