
Java中的委派不是语法特性,而是一种靠组合+接口+运行时选择实现的对象协作方式——它不靠 extends,而是让一个对象“请”另一个对象干活。
什么时候该用委派,而不是继承?
当你想复用某类逻辑,但又不想暴露它的全部 API、也不愿被它的父类约束时,委派就是更干净的选择。比如你有个 FileProcessor 类封装了读写逻辑,但你不希望业务类成为它的子类(否则得重写一堆钩子方法),这时就该把它作为字段持有并转发调用。
- 继承适用于「is-a」关系(
Car extends Vehicle),委派适用于「uses-a」或「has-a」关系(ReportGenerator uses PDFExporter) - 继承在编译期绑定,改父类可能破坏子类;委派在运行时决定委托对象,可动态替换(比如根据配置切换
CloudStorage或LocalStorage) - 继承容易导致类层次过深,委派天然扁平——一个类可以同时委派给多个不同职责的对象
TaskDelegate 这类典型写法为什么容易出错?
很多教程直接在 doTask() 里 new 具体实现类,看似简单,实则埋雷:每次调用都新建实例,无法复用状态、无法注入依赖、无法做单元测试 mock。
- 错误写法:
task = new ConcreteTaskA();—— 硬编码、不可测、生命周期失控 - 正确做法:通过构造器或 setter 注入
Task实例,或者用工厂/ServiceLoader 解耦创建逻辑 - 若需策略切换(如按用户角色选处理器),别用
Random或硬写 if-else,改用Map<string task></string>查表,或结合 Spring 的@Qualifier自动装配
委派和代理(Proxy)、策略(Strategy)怎么分清?
三者代码结构有时相似,但意图完全不同:委派关注「谁来执行」,代理关注「执行前后加控制」,策略关注「算法可替换」。
立即学习“Java免费学习笔记(深入)”;
- 委派类(
TaskDelegate)通常不改写行为,只是路由请求——它自己不实现业务,只做中转 - 代理类(如 JDK 动态代理)必须实现相同接口,但会在调用前后插入日志、事务、权限等横切逻辑
- 策略类(
PaymentStrategy)强调算法族的统一抽象,客户端明确选择并持有某一种,不负责决策逻辑 - 一个类可以同时是委派者 + 代理者(比如先委派给具体实现,再由代理包装其调用),但不能混淆设计意图
真正难的不是写对委派结构,而是判断「这个职责到底该由谁拥有」。很多人把本该属于领域对象的逻辑塞进委派类,结果委派类越来越胖,成了新的上帝类——这时候就得停下来,重新划清边界。










