Matlab迭代器模式
迭代器(Iterator)模式,又叫做游标(Cursor)模式。提供一种方法访问一个容器(container)或者聚集(Aggregator)对象中各个元素,而又不需暴露该对象的内部细节。在采用不同的方式迭代时,只需要替换相应Iterator类即可。本文采用Matlab语言实现对元胞数组和string数组的遍历。
Aggregator.m
classdef Aggregator < handle methods(Abstract) iterObj = createIterator(~); end end
CellAggregator.m
classdef CellAggregator < Aggregator properties cell end methods function obj = CellAggregator(cell) obj.cell = cell; end function iterObj = createIterator(obj) iterObj = CellIterator(obj); end end end
StringAggregator.m
classdef StringAggregator < Aggregator properties string_arr end methods function obj = StringAggregator(string_arr) obj.string_arr = string_arr; end function iterObj = createIterator(obj) iterObj = StringIterator(obj); end end end
Iterator.m
classdef Iterator < handle methods(Abstract) hasNext(~); next(~); end end
CellIterator.m
classdef CellIterator < Iterator properties index = 1; aggHandle; end methods function obj = CellIterator(agg) obj.aggHandle = agg; end function res = hasNext(obj) if(obj.index <= length(obj.aggHandle.cell)) res = true; else res = false; end end function ele = next(obj) if(obj.hasNext()) ele = obj.aggHandle.cell{obj.index}; obj.index = obj.index + 1; else ele = []; end end end end
StringIterator.m
classdef StringIterator < Iterator properties index = 1; aggHandle; end methods function obj = StringIterator(agg) obj.aggHandle = agg; end function res = hasNext(obj) if(obj.index <= obj.aggHandle.string_arr.length) res = true; else res = false; end end function ele = next(obj) if(obj.hasNext()) ele = obj.aggHandle.string_arr(obj.index); obj.index = obj.index + 1; else ele = string.empty(); end end end end
测试代码:
cell = CellAggregator({\'matlab\',\'cell\',\'iter\'}); iterObj = cell.createIterator(); while iterObj.hasNext() disp(iterObj.next()); end str_arr = StringAggregator(["matlab","string","iter"]); iterObj = str_arr.createIterator(); while iterObj.hasNext() disp(iterObj.next()); end
迭代器模式不仅可以对集合进行顺序遍历,而且可以以用户想要的条件进行遍历,如果想要统计列表中所有偶数的和,可以写成循环语句,如下所示:
test_for.m
list = [13,8,17,11,8,19,18,12,13,12]; sum = 0; for i=1:length(list) if mod(list(i),2) == 0 sum = sum + list(i); end end disp("列表中所有偶数的和:" + sum); sum = 0; for i=1:length(list) if mod(list(i),2) == 1 sum = sum + list(i); end end disp("列表中所有奇数的和:" + sum);
如果要统计列表中所有奇数的和,这就需要对循环语句块进行修改,如上所示。这就违反了对修改关闭的原则。而迭代器模式可以将循环语句块和业务语句块(sum求和)分离出去,这就需要对Aggregator和Iterator类进行继承,如下所示:
ListAggregator.m
classdef ListAggregator < Aggregator properties(Constant) EVEN_ITER = 0 ODD_ITER = 1 end properties list end methods function obj = ListAggregator(list) obj.list = list; end function iterObj = createIterator(obj,type_iter) if(type_iter == ListAggregator.EVEN_ITER) iterObj = EvenIterator(obj); else iterObj = OddIterator(obj); end end end end
OddIterator.m
classdef OddIterator < Iterator properties index = 1; aggHandle; end methods function obj = OddIterator(agg) obj.aggHandle = agg; end function res = hasNext(obj) res = false; while(obj.index <= length(obj.aggHandle.list)) if mod(obj.aggHandle.list(obj.index),2) == 1 res = true; break; end obj.index = obj.index + 1; end end function ele = next(obj) if(obj.hasNext()) ele = obj.aggHandle.list(obj.index); obj.index = obj.index + 1; else ele = []; end end end end
EvenIterator.m
classdef EvenIterator < Iterator properties index = 1; aggHandle; end methods function obj = EvenIterator(agg) obj.aggHandle = agg; end function res = hasNext(obj) res = false; while(obj.index <= length(obj.aggHandle.list)) if mod(obj.aggHandle.list(obj.index),2) == 0 res = true; break; end obj.index = obj.index + 1; end end function ele = next(obj) if(obj.hasNext()) ele = obj.aggHandle.list(obj.index); obj.index = obj.index + 1; else ele = []; end end end end
test_iter.m
list_agg = ListAggregator([13,8,17,11,8,19,18,12,13,12]); iterObj = list_agg.createIterator(ListAggregator.EVEN_ITER); sum = 0; while iterObj.hasNext() sum = sum + iterObj.next(); end disp("列表中所有偶数的和:" + sum); iterObj = list_agg.createIterator(ListAggregator.ODD_ITER); sum = 0; while iterObj.hasNext() sum = sum + iterObj.next(); end disp("列表中所有奇数的和:" + sum);
如果需要返回列表标,可以将next函数的返回值定义成[ele,index] = next(obj),python里面有yield关键字,可以让迭代器模式更加简洁,见参考资料。
迭代器模式还可以扁平化多层嵌套循环,如果找到所有水仙花数,可以使用三层循环,代码如下:
test_for.m
a = 1:9; b = 0:9; c = 0:9; for i=1:length(a) for j = 1:length(b) for k = 1:length(c) num = a(i)*100 + b(j)*10 + c(k); if a(i)^3 + b(j)^3 + c(k)^3 == a(i)*100 + b(j)*10 + c(k) disp("" + num + "是水仙花数"); end end end end
如果使用迭代器模式来简化三层循环,只需要对Aggregator和Iterator类进行继承,代码如下:
MutiListAggregator.m
classdef MutiListAggregator < Aggregator properties lists end methods function obj = MutiListAggregator(varargin) obj.lists = varargin; end function iterObj = createIterator(obj) iterObj = MutiListIterator(obj); end end end
MutiListIterator.m
classdef MutiListIterator < Iterator properties indexs = []; lengths = []; aggHandle; end methods function obj = MutiListIterator(agg) obj.aggHandle = agg; for i= 1:length(obj.aggHandle.lists) obj.lengths(i) = length(obj.aggHandle.lists{i}); end obj.indexs = ones(1,length(obj.aggHandle.lists)); end function res = hasNext(obj) if(obj.indexs(1) > obj.lengths(1)) res = false; else res = true; end end function varargout = next(obj) if(obj.hasNext()) for i = 1:length(obj.aggHandle.lists) temp_list = obj.aggHandle.lists{i}; varargout{i} = temp_list(obj.indexs(i)); end obj.indexs(length(obj.aggHandle.lists)) = obj.indexs(length(obj.aggHandle.lists)) + 1; for i = length(obj.aggHandle.lists):-1:2 if(obj.indexs(i) > obj.lengths(i)) obj.indexs(i) = mod(obj.indexs(i), obj.lengths(i)); obj.indexs(i - 1) = obj.indexs(i - 1) + 1; end end else for i = 1:length(obj.aggHandle.lists) varargout{i} = []; end end end end end
test_iter.m
list_agg = MutiListAggregator(1:9,0:9,0:9); iterObj = list_agg.createIterator(); while iterObj.hasNext() [a,b,c] = iterObj.next(); num = a * 100 + b * 10 + c; if a^3 + b^3 + c^3 == a * 100 + b * 10 + c disp("" + num + "是水仙花数"); end end
参考资料:
https://mp.weixin.qq.com/s/tghaVkTPUijBJO0qxSXdZQ
请发表评论