封装是围绕访问控制、变更影响和解耦设计的系统性实践,需通过private字段、受控方法、不可变返回、业务语义命名、接口抽象及主动契约设计来实现真正保护与灵活性。

封装不是加个 private 就完事,而是围绕“谁该访问”“怎么访问”“改了会不会牵一发而动全身”做系统性设计。核心变量一旦裸露,数据安全和模块稳定就同时失守;而真正有效的封装,能让保护和解耦同步落地。
把业务关键字段设为 private,并只留受控入口
比如电商系统中的商品库存、用户余额、订单状态等,直接 public 或包级可见会引发大量硬编码依赖。必须强制走方法访问,才能嵌入校验、审计、通知等横切逻辑。
- 字段声明用
private,不提供无条件的 setter —— 例如setBalance(double)内部要判断是否为负、是否超阈值、是否触发风控回调 - getter 也不只是简单返回,可加入访问计数、过期检查或懒加载逻辑(如首次调用才从缓存加载)
- 避免暴露可变对象引用:若字段是
private List<order> orders</order>,getter 应返回Collections.unmodifiableList(orders),防止外部修改破坏内部一致性
把多变逻辑收进方法,让调用方只认接口不认实现
业务规则常变,比如优惠计算从“满300减50”升级为“会员等级+时段+品类叠加”。如果各处都手动写公式,改一处漏十处;而封装后,所有页面、服务、定时任务都只调 getFinalPrice(),改一个地方全生效。
- 把计算、组装、转换类逻辑全部移到类内部,外部不拼字段、不重复 if-else
- 方法命名体现业务语义,如
canApplyVoucher()比checkRule()更明确职责 - 必要时将策略抽象成接口(如
PricingStrategy),当前类只持有一个策略实例,替换策略不改调用方代码
用接口而非具体类定义依赖关系
模块之间如果直接 new 具体类或强依赖某个实现类,等于把对方的字段名、构造方式、生命周期全绑死了。用接口暴露能力,才是解耦的关键一步。
- 支付模块对外只暴露
PaymentService.pay(Order),不暴露微信 SDK 的WXPayApi或支付宝的AlipayClient - 仓储层统一用
UserRepository接口,上层服务不关心底层是 MySQL、MongoDB 还是内存 Map - Android 中 Activity 状态管理不暴露
LiveData<boolean></boolean>字段,而是提供isLoginReady(): Boolean和observeLoginState(observer)两个明确语义的方法
警惕“伪封装”:getter/setter 不等于封装完成
自动生成的 getter/setter 若不做校验、不加日志、不处理并发、不隔离副作用,只是披了层皮的 public 字段。真正的封装需要主动设计访问契约。
- setter 中必须包含业务校验:年龄不能负、手机号格式要对、状态迁移要合法(如“已发货”不能直接回退到“待付款”)
- 敏感字段(如密码、token)只提供
encodeAndSet(),不提供 getter;或 getter 返回空/掩码值 - 避免在 setter 中启动耗时操作(如网络请求、数据库写入),这类行为应显式拆成独立方法(如
syncToCloud()),让调用方清楚感知代价

















