概述
文章首发于知乎专栏:
https://zhuanlan.zhihu.com/c_1136684995157577728
个人公众号TarysThink
模板方法模式之后讲迭代器模式(Iterator)再合适不过。我始终认为,迭代器模式是一种特殊的模板方法模式。看这一篇有困难的同学最好回头再看一下上一篇:模板方法模式,当然,我也会从头开始讲故事,不必过分担心必须有模板方法模式的基础。
这篇篇幅会比较长,所以我们就直入主题。
操场上排了一排小学生,既有数据结构是顺序链表,也就是说用链表遍历节点的方式去遍历这些小学生。有这个一个需求,遍历小学生,遍历到的节点执行操作:printf("今天天气真好%d"); printf("今天你也很好看%d");,%d的位置打印出节点结构下的变量a。李逵的函数实现如下:
void ForeachStudent()
{
Node head = GetHeadNode();//获取头节点
Node pos = head;
ListForeach(head, pos)//遍历链表操作的封装
{
printf("今天天气真好%d", ((Student *)pos)->a));//节点结构体为Student,其第一个成员为Node
printf("今天你也很好看%d", ((Student *)pos)->a));
}
}
上面这段代码封装性很好,特别是对链表具体操作的封装。
此时又来一个需求,业务方案要求在代码中的另一处也遍历小学生队列,但打印内容不同:printf("今天真热%d"); printf("体育课真累%d");,%d的位置打印出节点结构下的变量b。李逵同学的函数实现如下:
void ForeachStudentSayHot()
{
Node head = GetHeadNode();//获取头节点
Node pos = head;
ListForeach(head, pos)//遍历链表操作的封装
{
printf("今天真热%d", ((Student *)pos)->b));//节点结构体为Student,其第一个成员为Node
printf("体育课真累%d", ((Student *)pos)->b));
}
}
宋江同学一看,这不行,这个需求引入后,原来的函数名必须改,哪怕改成ForeachStudentSayNice也好。
宝玉一看,觉得他们境界太低,简单一看代码里这么多重复,“你们难道没有消除重复的冲动吗?”,宝玉代码如下:
typedef void (*Say)(Node pos);
ForeachStudent(Say say)
{
Node head = GetHeadNode();//获取头节点
Node pos = head;
ListForeach(head, pos)//遍历链表操作的封装
{
say(pos);
}
}
void SayNice(Node pos)
{
printf("今天天气真好%d", ((Student *)pos)->a));//节点结构体为Student,其第一个成员为Node
printf("今天你也很好看%d", ((Student *)pos)->a));
}
void SayHot(Node pos)
{
printf("今天真热%d", ((Student *)pos)->b));//节点结构体为Student,其第一个成员为Node
printf("体育课真累%d", ((Student *)pos)->b));
}
//第一处调用
ForeachStudent(SayNice);
//第二处调用
ForeachStudent(SayHot);
旁边的贾政同学道:”这个代码写得非常好,SayNice和SayHot完全感知不到学生列表的具体组织形式。将来某一天发现链表的结构无法满足需求,你可以很便捷地修改外层的数据结构遍历函数,内部的处理函数不需要修改,这就是迭代器模式的核心思想。文章开头说,迭代器模式与模板方法模式非常相似,就是在这种层面上的相似,我们可以把外层循环看做一个模板,那么这就是一个模板方法模式了。”
贾政继续道:“这个方法有一些缺点。假如你想在遍历循环里加入break和continue语句,而且不同调用点的break和continue条件不同,那么你就需要在入参里把具体处理都传进去,随着变化方向的增多,带来的管理的复杂度越来越难以控制,代码将很难看懂。”
扩展阅读:
程序员诸葛亮亮说:“熟练掌握上面宝玉同学的代码写法,已足够写好结构遍历的绝大多数代码。而且这种方法已经符合了迭代器模式的设计思想,按C语言思想描述起来也非常简单和实用。设计模式里讲的迭代器模式,比宝玉的代码稍复杂些,它提供了更多更复杂的功能。我们回看ForeachStudent函数,它内部调用了链表操作专门的ListForeach函数,而且获取了链表头节点,这意味着,当我们将链表改成数组时,这些都将是阻碍。那有没有办法把这些信息对ForeachStudent也隐藏起来呢?有,再做些抽象,我们下回分解”。
最后
以上就是动听跳跳糖为你收集整理的C常用设计模式——迭代器模式的全部内容,希望文章能够帮你解决C常用设计模式——迭代器模式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复