上一篇地址:持续总结中!2024年面试必问 20 道设计模式面试题(五)-CSDN博客
十一、迭代器模式(Iterator Pattern)解决了什么问题?
迭代器模式(Iterator Pattern)解决了如何顺序访问一个聚合对象中的各个元素,而不暴露其内部的表示的问题。这种模式定义了一种方法来遍历集合,同时保持了对象的封装性,并且允许在不修改现有代码的情况下添加新的迭代方式。
迭代器模式解决的问题:
-
访问聚合对象的统一接口:不同的聚合对象可能有不同的内部结构,迭代器模式提供了一种统一的方法来访问它们的元素。
-
封装变化:迭代器模式隐藏了聚合对象的具体实现细节,如果聚合对象的内部表示改变,只要迭代器的接口保持不变,客户端代码就不需要修改。
-
支持多种遍历方式:可以在同一个聚合对象上定义多个迭代器,以不同的方式遍历集合,例如正向迭代、逆向迭代等。
-
提供了一种方式来避免在聚合对象中直接暴露其元素:这有助于保护对象的完整性和封装性。
-
简化客户端代码:客户端代码通过迭代器与聚合对象交互,而不需要了解如何遍历聚合对象。
-
提供了一种机制来在迭代过程中修改聚合对象:某些迭代器模式的实现允许在迭代过程中安全地添加或删除元素。
迭代器模式的组成部分:
-
迭代器(Iterator):定义了访问和遍历元素的接口,如
hasNext()
和next()
方法。 -
具体迭代器(Concrete Iterator):实现了迭代器接口,并保持了一个当前位置的引用,以便知道在遍历过程中当前所处的位置。
-
聚合(Aggregate):定义了一个创建迭代器的方法,通常是一个
createIterator()
方法。 -
具体聚合(Concrete Aggregate):实现了聚合接口,并返回一个具体迭代器的实例,用于遍历集合。
迭代器模式的实际应用:
-
集合框架:在很多编程语言的集合框架中,迭代器模式被广泛使用,如Java中的
Iterator
接口。 -
数据结构:在实现复杂的数据结构,如树、图等时,迭代器模式可以提供一种统一的方法来遍历元素。
-
复杂对象集合:在需要遍历具有复杂内部结构的对象集合时,迭代器模式可以简化访问过程。
-
访问控制:在需要控制对集合元素的访问权限时,迭代器模式可以提供一种灵活的方式来实现。
示例:
假设有一个数字列表,我们希望以不同的方式遍历这个列表。使用迭代器模式,我们可以这样实现:
// 聚合接口
interface Aggregate {
Iterator createIterator();
}
// 具体聚合
class NumberList implements Aggregate {
private List<Integer> numbers;
public NumberList(List<Integer> numbers) {
this.numbers = numbers;
}
@Override
public Iterator createIterator() {
return new NumberIterator(this.numbers);
}
}
// 迭代器接口
interface Iterator {
boolean hasNext();
Integer next();
}
// 具体迭代器
class NumberIterator implements Iterator {
private List<Integer> numbers;
private int position = 0;
public NumberIterator(List<Integer> numbers) {
this.numbers = numbers;
}
@Override
public boolean hasNext() {
return position < numbers.size();
}
@Override
public Integer next() {
return numbers.get(position++);
}
}
// 客户端代码
Aggregate numberList = new NumberList(Arrays.asList(1, 2, 3, 4, 5));
Iterator iterator = numberList.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
在这个例子中,NumberList
是具体聚合,它实现了聚合接口并提供了一个列表的迭代器。NumberIterator
是具体迭代器,实现了迭代器接口,用于遍历列表中的数字。客户端代码通过聚合的createIterator()
方法获取迭代器,并使用迭代器来访问列表中的每个元素。这样,即使NumberList
的内部实现改变,客户端代码也可以不受影响。
十二、组合模式(Composite Pattern)和装饰器模式有何相似之处?
组合模式(Composite Pattern)和装饰器模式(Decorator Pattern)虽然在目的和应用场景上有所不同,但它们在某些方面存在相似之处:
-
对象结构的灵活性:两种模式都允许动态地构建和修改对象的结构。在组合模式中,可以在运行时向组合对象中添加或删除子组件。在装饰器模式中,可以在运行时向对象添加装饰者,以增加额外的职责。
-
树形结构的表示:组合模式通常用于表示树形结构的对象,允许客户端以一致的方式处理个别对象和组合对象。装饰器模式也可以用于构建类似树形的结构,通过多层装饰者来逐层增加对象的功能。
-
客户端透明性:两种模式都提供了客户端透明性。在组合模式中,客户端不需要区分叶节点和组合节点,因为它们共享相同的接口。在装饰器模式中,客户端不需要区分原始对象和装饰后的对象,因为它们也共享相同的接口。
-
递归的使用:在两种模式中,递归是一种常见的实现方式。组合模式中的组合对象可能会递归地调用其子组件的方法。装饰器模式中的装饰者可能会递归地委托给被装饰对象的方法。
-
组合/装饰的灵活性:两种模式都允许灵活地组合或装饰对象。在组合模式中,可以灵活地组合不同的对象来形成复杂的结构。在装饰器模式中,可以灵活地添加多个装饰者来增加不同的功能。
-
设计原则的遵循:两种模式都遵循了一些共同的设计原则,如开放封闭原则(对扩展开放,对修改封闭)。它们允许在不修改现有代码的基础上扩展对象的行为。
尽管存在上述相似之处,但组合模式和装饰器模式在目的和应用上有明显的区别:
- 组合模式主要用于创建树形结构的对象,强调的是部分与整体的统一,使得客户端可以一致地处理树中的所有对象。
- 装饰器模式主要用于动态地给单个对象添加额外的职责,强调的是功能的扩展,而不影响其他对象。
在实际应用中,根据具体的需求和场景,选择合适的模式来设计和实现系统。