Java 中 组合 (Composition)、接口 (Interface) 和 委托 (Delegation) 这三个概念的区别
备注:
1、本文内容大部分内容是通过AI查询而来的。然后我进行了总结和修改。
2、本文是在学习极客时间王争老师的《设计模式之美》-《10 | 理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?》时,所做的一些记录和思考。
本文将讲解一下 Java 中 组合 (Composition)、接口 (Interface) 和 委托 (Delegation) 这三个概念的区别,并通过 Java 代码示例进行说明。
| 特性 | 组合 (Composition) | 接口 (Interface) | 委托 (Delegation) | 
| 定义 | 类 A 包含类 B 的一个实例作为其成员变量。 | 定义一组方法签名,但不提供实现。 | 类 A 将某些职责交给类 B 的实例来完成。 | 
| 关系 | “拥有” (has-a) 关系。 | “契约” 或 “能力” 关系。 | “转交” (forwarding) 职责。 | 
| 目的 | 重用现有类的功能,实现功能聚合。 | 实现多态,定义公共行为规范,解耦实现。 | 在不使用继承的情况下实现代码重用和功能扩展。 | 
| 实现 | 通过在类中创建另一个类的对象实例。 | 通过 interface 关键字和 implements 关键字。 | 通过组合,并在包含类中显式地调用成员对象的方法。 | 
| 优点 | 高度灵活,可以随时替换内部对象。 | 强制实现约定方法,支持多重实现。 | 替代继承,提供更灵活的运行时行为。 | 
1. 接口 (Interface)
接口定义了对象可以做什么(能力/行为),而不关心如何实现。
/*** 接口:定义“可打印”的能力*/
public interface Printable {// 定义一个打印方法,所有实现该接口的类都必须实现此方法void print(String content);
}/*** 实现类 A:激光打印机*/
public class LaserPrinter implements Printable {@Overridepublic void print(String content) {System.out.println("激光打印机正在高速打印: " + content);}
}/*** 实现类 B:喷墨打印机*/
public class InkjetPrinter implements Printable {@Overridepublic void print(String content) {System.out.println("喷墨打印机正在彩色打印: " + content);}
}关键点: Printable 定义了契约,LaserPrinter 和 InkjetPrinter 提供了不同的实现,实现了多态。
2. 组合 (Composition)
组合是类 A 拥有类 B 的实例,从而重用类 B 的功能。
/*** 使用组合的 Document 类* Document “拥有”一个 LaserPrinter 实例*/
public class Document {// 1. 组合:Document 内部有一个 LaserPrinter 的实例 (has-a 关系)private LaserPrinter myPrinter; public Document() {// 实例化内部对象this.myPrinter = new LaserPrinter();}public void printMyDocument(String text) {System.out.println("--- Document 准备打印 ---");// 2. Document 使用其内部 Printer 的功能myPrinter.print(text); System.out.println("--- 打印完成 ---");}
}关键点: Document 不需要知道如何打印,它将打印工作委托给内部的 LaserPrinter 对象完成。
3. 委托 (Delegation)
委托是一种设计模式,它结合了组合和接口。一个对象(委托者)将自己的某个操作的实现交给另一个对象(被委托者)来完成。这是组合的更灵活的用途,通常用于替代继承。
/*** 使用委托的 SmartPrinter 类* SmartPrinter 将打印的职责委托给一个实现了 Printable 接口的对象*/
public class SmartPrinter implements Printable {// 1. 组合:SmartPrinter 拥有一个 Printable 类型的成员变量private Printable delegatePrinter; // 构造函数:运行时可以决定使用哪种打印机 (高度灵活)public SmartPrinter(Printable printer) {this.delegatePrinter = printer;}// 2. 委托:SmartPrinter 实现 Printable 接口,并将实现转交给内部对象@Overridepublic void print(String content) {System.out.println("SmartPrinter 正在处理请求...");// 显式委托调用:将实际工作转发给 delegatePrinterdelegatePrinter.print(content); System.out.println("SmartPrinter 完成转发。");}
}// --- 运行示例 ---
public class Main {public static void main(String[] args) {// 1. 创建被委托者(一个 InkjetPrinter)Printable inkjet = new InkjetPrinter(); // 2. 创建委托者,将被委托者传入SmartPrinter smartPrinter = new SmartPrinter(inkjet);// 3. 调用委托者的方法,实际工作由被委托者完成smartPrinter.print("项目报告 V3.0"); // 4. 运行时可以改变内部对象(这是委托比继承更灵活的地方)SmartPrinter newSmartPrinter = new SmartPrinter(new LaserPrinter());newSmartPrinter.print("紧急通知");}
}关键点: SmartPrinter 的 print 方法简单地调用了内部 delegatePrinter 的 print 方法,这就是 委托。它实现了 Printable 接口(契约),并通过 组合(拥有内部对象)来完成功能。
总而言之:
接口是定义能力 (What) 的契约。
组合是定义拥有关系 (Has-a) 的结构。
委托是一种设计模式,利用组合来实现接口定义的行为,转交职责。
