【愚公系列】2023年10月 二十三种设计模式(十六)-迭代器模式(Iterator Pattern)
🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,腾讯云优秀博主,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏
🚀前言
设计模式(Design Pattern)是软件开发领域的宝贵经验,是多人反复借鉴和广泛应用的代码设计指导。它们是一系列经过分类和归纳的代码组织方法,旨在实现可重用性、可维护性和可理解性。使用设计模式,我们能够编写高质量的代码,使其更易于他人理解,并提供了代码可靠性的保证。
毫无疑问,设计模式对个人、团队和整个系统都带来了显著的益处。它们将代码开发提升到工程化水平,为软件工程构建提供了坚实的基础,就如同大厦的一块块精巧的砖石一样。在项目中明智地应用设计模式可以完美地解决各种复杂问题。每种设计模式都有相应的原理和最佳实践,它们描述了我们日常开发中不断遇到的问题,以及这些问题的核心解决方法。正是因为这种实用性和通用性,设计模式才能在软件开发中广泛地得以应用。设计模式是构建稳健、可扩展和可维护软件的关键工具,为开发者们提供了解决问题的智慧和指导。
🚀一、迭代器模式(Iterator Pattern)
迭代器模式,作为一种行为型设计模式,旨在提供一种有序遍历聚合对象中各元素的机制,同时又不需暴露该聚合对象的内部结构。这样设计既保护了集合的封装性,又使得外部代码能够透明、方便地访问聚合内部的数据。简而言之,迭代器模式允许我们遍历集合,而无需了解集合的底层实现细节。这一模式的应用使得代码更具可维护性和扩展性
🚀二、使用步骤
🔎1.角色
🦋1.1 迭代器(Iterator)
解释器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern)是两种不同的设计模式,它们分别解决不同的问题,但在某些情况下可以一起使用。
解释器模式(Interpreter Pattern):
- 解释器模式用于定义一种语言的文法规则,并提供一种解释器来解释该语言中的表达式。这种模式通常用于构建领域特定语言(DSL)的解释器或规则引擎。解释器模式的主要作用是解释和执行特定语法规则或表达式,而不暴露其内部实现细节。
迭代器模式(Iterator Pattern):
- 迭代器模式用于提供一种访问集合对象元素的方式,而不需要暴露集合内部的表示。它定义了一个迭代器接口,包括诸如获取下一个元素、判断是否还有元素等方法,以允许客户端代码按顺序访问集合的元素。迭代器模式的主要作用是将集合的遍历行为抽象出来,使得客户端代码可以统一地遍历不同类型的集合,而不关心其底层结构。
虽然解释器模式和迭代器模式有不同的目的,但它们可以在某些情况下协同工作。特别是在解释器模式中,当需要解释的语法规则涉及到集合的操作时,可以使用迭代器模式来帮助解释器遍历集合中的元素。
例如,假设我们正在构建一个SQL查询解释器,其中的查询结果是一个集合,我们可以使用迭代器模式来遍历查询结果集合,同时使用解释器模式来解释SQL查询语句中的条件和操作。
迭代器模式用于访问集合元素,解释器模式用于解释和执行语法规则或表达式,它们可以在某些情况下协同工作,特别是当解释器需要操作集合时。这种协同工作可以使代码更具灵活性和可维护性。
🦋1.2 具体迭代器(Concrete Iteraror)
在解释器模式(Interpreter Pattern)中,并没有直接与“具体迭代器(Concrete Iterator)”相关的概念。解释器模式主要关注语法解释和表达式求值,而不是集合遍历。具体迭代器通常是与迭代器模式相关的设计模式中的概念。
具体迭代器是迭代器模式中的一部分,用于实现迭代器接口,提供了对集合内部元素的访问方法,以允许客户端代码按顺序遍历集合的元素。具体迭代器通常包含以下方法:
hasNext()
:判断是否还有下一个元素可以遍历。next()
:获取下一个元素。- 可能还包括其他方法,如
remove()
,用于从集合中删除元素(不是必须的,取决于具体实现)。
具体迭代器的作用是将集合的遍历行为封装在一个独立的对象中,使得客户端代码可以统一地访问不同类型的集合,而不需要了解集合的内部结构。
解释器模式,相反,用于定义一种语言的文法规则,并提供一种解释器来解释该语言中的表达式。解释器模式主要关注于解释和执行特定语法规则或表达式,而不是集合的遍历。它通常用于构建领域特定语言(DSL)的解释器或规则引擎。
虽然解释器模式和迭代器模式都涉及到模式的解释,但它们的焦点和作用领域是不同的。解释器模式处理语法解释,而迭代器模式处理集合的遍历。因此,在解释器模式中,并没有直接与“具体迭代器”相关的概
🦋1.3 聚合(Aggregate)
在解释器模式(Interpreter Pattern)中,并没有直接与“聚合(Aggregate)”相关的概念和作用。解释器模式主要关注语法解释和表达式求值,而聚合通常是与其他设计模式,如迭代器模式(Iterator Pattern)相关的概念。
聚合是迭代器模式中的一个概念,它代表一个集合或容器对象,可以包含多个元素。聚合对象通常实现了一个迭代器接口,允许客户端代码按顺序遍历其中的元素。迭代器模式的作用是提供一种访问集合内部元素的方式,同时隐藏了集合的内部表示,使得客户端代码可以统一地遍历不同类型的集合,而不需要了解集合的具体实现细节。
在迭代器模式中,聚合对象通常具有以下角色:
聚合接口(Aggregate Interface):定义了聚合对象的基本操作,如创建迭代器的方法。
具体聚合(Concrete Aggregate):实现了聚合接口,表示具体的聚合对象,例如列表、栈、队列等。
迭代器接口(Iterator Interface):定义了迭代器对象的方法,包括获取下一个元素、判断是否还有元素等。
具体迭代器(Concrete Iterator):实现了迭代器接口,提供了对聚合对象元素的遍历操作。
聚合对象在迭代器模式中用于封装集合内部的元素,并提供一种统一的方式来访问这些元素。解释器模式与聚合无直接关联,它主要关注语法解释和表达式求值,通常用于构建领域特定语言(DSL)的解释器或规则引擎。如果你需要处理集合的遍历,那么迭代器模式会更为适合。
🦋1.4 具体聚合(Concrete Aggregate)
在解释器模式(Interpreter Pattern)中,并没有直接与“具体聚合(Concrete Aggregate)”相关的概念和作用。解释器模式主要关注语法解释和表达式求值,而聚合通常是与其他设计模式,如迭代器模式(Iterator Pattern)相关的概念。
具体聚合是迭代器模式中的一个概念,而不是解释器模式中的概念。迭代器模式用于提供一种访问集合对象元素的方式,同时隐藏了集合的内部表示,使得客户端代码可以统一地遍历不同类型的集合,而不需要了解集合的具体实现细节。具体聚合通常是实现了聚合接口(Aggregate Interface)的对象,用于代表特定类型的集合,如列表、栈、队列等。
在迭代器模式中,聚合对象通常具有以下角色:
聚合接口(Aggregate Interface):定义了聚合对象的基本操作,如创建迭代器的方法。
具体聚合(Concrete Aggregate):实现了聚合接口,表示具体的聚合对象,例如列表、栈、队列等。具体聚合对象会提供用于创建具体迭代器的方法。
迭代器接口(Iterator Interface):定义了迭代器对象的方法,包括获取下一个元素、判断是否还有元素等。
具体迭代器(Concrete Iterator):实现了迭代器接口,提供了对聚合对象元素的遍历操作。
具体聚合是迭代器模式中的一个概念,它表示特定类型的集合对象,并实现了聚合接口。解释器模式与聚合无直接关联,解释器模式主要关注语法解释和表达式求值,通常用于构建领域特定语言(DSL)的解释器或规则引擎。如果你需要处理集合的遍历,那么迭代器模式会更为适合。
🔎2.示例
命名空间IteratorPattern中包含Person基类、People类、PelpleEnum类,另外包含一个苹果手机ApplePhone类,和BestEnum类。Person示例来自微软官方的 IEnumerable接口 介绍页面,BestEnum则使用.Net 2.0中的yield return关键字创建苹果手机信息序列。
namespace IteratorPattern
🦋2.1 传统迭代器实现
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public Person(string firstName, string lastName) {
this.FirstName = firstName;
this.LastName = lastName;
}
}
Person类,包含First Name和Last Name。
public class People : IEnumerable {
private Person[] _people = null;
public People(Person[] pArray) {
_people = new Person[pArray.Length];
for (int i = 0; i < pArray.Length; i++) {
_people[i] = pArray[i];
}
}
public IEnumerator GetEnumerator() {
return new PeopleEnum(_people);
}
}
People类,实现IEnumerable接口。
public class PeopleEnum : IEnumerator {
private Person[] _people = null;
private int _cursor = -1;
public PeopleEnum(Person[] list) {
_people = list;
}
public bool MoveNext() {
_cursor++;
return (_cursor < _people.Length);
}
public void Reset() {
_cursor = -1;
}
public object Current {
get {
try {
return _people[_cursor];
}
catch (IndexOutOfRangeException) {
throw new InvalidOperationException();
}
}
}
}
PeopleEnum类,实现IEnumerator接口。
🦋2.2 yield return迭代器实现
yield关键字向编译器指示它所在的方法是迭代器块,yield return返回一个迭代器的状态机。
public class ApplePhone {
public string PhoneName { get; set; }
public DateTime PublishedDate { get; set; }
}
ApplePhone类,包含手机名称和发布日期。
public class BestEnum {
public static IEnumerable<ApplePhone> GetIPhones() {
yield return new ApplePhone {
PhoneName = "IPhone",
PublishedDate = new DateTime(2007, 1, 9)
};
yield return new ApplePhone {
PhoneName = "IPhone 3G",
PublishedDate = new DateTime(2008, 6, 10)
};
yield return new ApplePhone {
PhoneName = "IPhone 3GS",
PublishedDate = new DateTime(2009, 6, 9)
};
yield return new ApplePhone {
PhoneName = "IPhone 4",
PublishedDate = new DateTime(2010, 6, 8)
};
//部分代码已省略
}
}
BestEnum类,包含GetIPhones方法返回苹果手机信息的序列。
public class Program {
protected const string LINE_BREAK =
"---------------------------------------------";
public static void Main(string[] args) {
var peopleArray = new Person[]
{
new Person("John", "Smith"),
new Person("Jim", "Johnson"),
new Person("Sue", "Rabon")
};
var peopleList = new People(peopleArray);
foreach(Person p in peopleList)
Console.WriteLine(p.FirstName + " " + p.LastName);
Console.WriteLine(LINE_BREAK);
var iterator = peopleList.GetEnumerator();
while(iterator.MoveNext()) {
var person = iterator.Current as Person;
Console.WriteLine(person.FirstName + " " + person.LastName);
}
Console.WriteLine(LINE_BREAK);
foreach(var phone in BestEnum.GetIPhones()) {
Console.WriteLine("[" + phone.PhoneName + "] was released in " +
phone.PublishedDate.ToString("yyyy-MM-dd") + "!");
}
Console.WriteLine(LINE_BREAK);
Console.ReadKey();
}
}
以上是调用方的代码,以下是这个案例的输出结果:
John Smith
Jim Johnson
Sue Rabon
---------------------------------------------
John Smith
Jim Johnson
Sue Rabon
---------------------------------------------
[IPhone] was released in 2007-01-09!
[IPhone 3G] was released in 2008-06-10!
[IPhone 3GS] was released in 2009-06-09!
[IPhone 4] was released in 2010-06-08!
[IPhone 4s] was released in 2011-10-04!
[IPhone 5] was released in 2012-09-13!
[IPhone 5S] was released in 2013-09-10!
[IPhone 5C] was released in 2013-09-10!
[IPhone 6] was released in 2014-09-10!
[IPhone 6 Plus] was released in 2014-09-10!
[IPhone 6s] was released in 2015-09-10!
[IPhone 6s Plus] was released in 2015-09-10!
[IPhone 7] was released in 2016-09-08!
[IPhone 7 Plus] was released in 2016-09-08!
[IPhone 8] was released in 2017-09-13!
[IPhone 8 Plus] was released in 2017-09-13!
[IPhone X] was released in 2017-09-13!
---------------------------------------------
🚀总结
🔎1.优点
迭代器模式(Iterator Pattern)有许多优点,它提供了一种有效的方式来访问和遍历集合对象的元素,同时也具有以下几个主要的优点:
分离集合对象和遍历行为:
- 迭代器模式将集合对象的遍历行为与集合对象本身分离开来,使得它们可以独立变化。这意味着你可以改变集合对象的内部结构而不影响客户端代码的遍历方式,反之亦然。
简化客户端代码:
- 客户端代码不需要了解集合对象的内部结构或实现细节,只需通过迭代器接口来访问元素,从而简化了客户端的代码逻辑。
支持多种遍历方式:
- 迭代器模式可以提供多种不同类型的迭代器,允许客户端代码以不同的方式遍历集合元素。例如,可以有正向迭代器、逆向迭代器等。
提供一致的遍历接口:
- 通过迭代器模式,不同类型的集合都可以提供一致的遍历接口,使得客户端代码可以统一处理不同类型的集合,提高了代码的灵活性和可维护性。
支持并发访问:
- 在某些情况下,迭代器模式可以支持并发访问,允许多个线程同时访问集合对象的元素,而不会发生冲突。
降低了集合对象的职责:
- 集合对象只需要负责存储和管理元素,而具体的遍历行为由迭代器来处理,降低了集合对象的职责,使其更加专注于管理元素。
迭代器模式提供了一种灵活、通用的方式来遍历集合对象的元素,同时降低了客户端代码与集合对象之间的耦合度,使得代码更易维护和扩展。这使得迭代器模式成为了许多编程语言和框架中常用的设计模式之一。
🔎2.缺点
虽然迭代器模式(Iterator Pattern)有许多优点,但也存在一些潜在的缺点和限制,这些缺点包括:
增加了复杂性:
- 引入迭代器模式会增加代码的复杂性,因为需要定义迭代器接口、具体迭代器类以及在集合中实现创建迭代器的方法。对于简单的集合,这可能会显得过于繁琐。
不适合所有集合类型:
- 迭代器模式并不适用于所有类型的集合。有些集合可能没有明确定义的迭代顺序,或者遍历元素的方式较为复杂,这时候使用迭代器模式可能不合适。
性能开销:
- 在某些情况下,使用迭代器模式可能会引入性能开销,特别是在大规模数据集合的情况下。迭代器需要维护状态信息以跟踪当前遍历位置,这可能会导致额外的内存和处理开销。
不直观:
- 对于简单的遍历需求,使用传统的循环语句可能更直观和简单,而引入迭代器模式可能会使代码变得复杂,不容易理解。
不利于逆向遍历:
- 某些集合对象的逆向遍历可能不容易实现,因为迭代器通常设计为单向遍历。要支持逆向遍历,可能需要额外的工作。
内存占用:
- 在某些情况下,迭代器可能需要占用额外的内存,特别是对于大型集合而言。这取决于具体的迭代器实现方式。
需要根据具体的使用场景和需求来判断是否使用迭代器模式,有时候简单的遍历可以通过其他方式更加高效地实现。在设计中要权衡迭代器模式的优点和缺点,确保它是适合问题的最佳解决方案。
🔎3.使用场景
迭代器模式(Iterator Pattern)适用于以下情况和场景:
需要遍历集合对象的元素:
- 当你有一个集合对象(如数组、列表、树等)并且需要遍历其中的元素,但不想暴露该集合的内部结构给客户端代码时,可以使用迭代器模式。
希望提供一致的遍历接口:
- 当你希望不同类型的集合对象都能够提供一致的遍历接口,使得客户端代码可以统一处理这些不同类型的集合时,迭代器模式非常有用。
需要支持多种遍历方式:
- 如果你希望能够以不同的方式遍历集合,例如正向遍历、逆向遍历、按条件过滤遍历等,迭代器模式可以提供多个不同类型的迭代器来满足这些需求。
要降低客户端代码与集合对象的耦合度:
- 迭代器模式可以将集合对象的遍历行为与其内部结构分离,从而降低了客户端代码与集合对象的耦合度,使得代码更加灵活和可维护。
需要在多线程环境下安全地遍历集合:
- 迭代器模式的某些实现可以支持多线程安全的遍历,这对于并发编程场景非常有用。
需要自定义迭代器的行为:
- 如果你希望能够自定义迭代器的行为,例如在遍历过程中执行特定的操作,迭代器模式允许你创建自定义的迭代器来满足这些需求。
迭代器模式在需要遍历集合对象的情况下,提供了一种通用、灵活且解耦的方式来进行元素遍历。它在许多编程语言和框架中都有广泛的应用,以提供一致的遍历接口和降低代码的复杂性。
🚀感谢:给读者的一封信
亲爱的读者,
我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。
如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。
我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。
如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。
再次感谢您的阅读和支持!
最诚挚的问候, “愚公搬代码”
- 点赞
- 收藏
- 关注作者
评论(0)