备注:
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 {
@Override
public void print(String content) {
System.out.println("激光打印机正在高速打印: " + content);
}
}
/**
* 实现类 B:喷墨打印机
*/
public class InkjetPrinter implements Printable {
@Override
public 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 接口,并将实现转交给内部对象
@Override
public void print(String content) {
System.out.println("SmartPrinter 正在处理请求...");
// 显式委托调用:将实际工作转发给 delegatePrinter
delegatePrinter.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) 的结构。
-
委托是一种设计模式,利用组合来实现接口定义的行为,转交职责。
Java中组合、接口与委托的区别
416

被折叠的 条评论
为什么被折叠?



