自定义滚动效果/树形结构遍历/分页加载…用迭代器掌控数据流动的节奏
假设你的社交应用需要显示以下内容:
这些数据来自不同接口,结构各异:
List<Post> cachedPosts = [...];
Stream<Message> realtimeMessages = [...];
List<Ad> ads = [...];
Future<List<FriendActivity>> friendActivities = [...];
传统遍历方式:
// 需要处理各种数据类型和异步状态
List<Widget> buildFeed() {
final widgets = <Widget>[];
// 添加缓存帖子
widgets.addAll(cachedPosts.map((p) => PostCard(p)));
// 添加广告
widgets.insert(2, AdCard(ads[0]));
// 处理实时消息
if (latestMessage != null) {
widgets.insert(0, MessageBubble(latestMessage));
}
// 异步加载朋友动态
friendActivities.then((activities) {
widgets.addAll(activities.map((a) => ActivityItem(a)));
});
return widgets;
}
问题爆发点:
核心思想: 提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部表示。
三个关键角色:
abstract class FeedContent {
Widget buildWidget();
int get priority; // 用于排序
bool get isAsync; // 是否异步加载
}
class PostContent implements FeedContent {
final Post post;
Widget buildWidget() => PostCard(post);
int get priority => 1;
bool get isAsync => false;
}
class AdContent implements FeedContent {
final Ad ad;
Widget buildWidget() => AdCard(ad);
int get priority => 3;
bool get isAsync => false;
}
class MessageContent implements FeedContent {
final Message message;
Widget buildWidget() => MessageBubble(message);
int get priority => 0; // 消息置顶
bool get isAsync => true;
}
class FeedIterator implements Iterator<FeedContent> {
final List<Iterator<FeedContent>> _iterators = [];
int _currentIndex = 0;
FeedIterator({
required List<Post> posts,
required List<Ad> ads,
required Stream<Message> messages,
}) {
// 初始化各数据源的迭代器
_iterators.add(posts.map((p) => PostContent(p)).iterator);
_iterators.add(ads.map((a) => AdContent(a)).iterator);
_iterators.add(messages.map((m) => MessageContent(m)).iterator);
// 按优先级排序
_iterators.sort((a, b) => a.current.priority.compareTo(b.current.priority));
}
FeedContent get current => _iterators[_currentIndex].current;
bool moveNext() {
// 先尝试移动当前迭代器
if (_iterators[_currentIndex].moveNext()) {
return true;
}
// 当前迭代器结束,切换到下一个
while (_currentIndex < _iterators.length - 1) {
_currentIndex++;
if (_iterators[_currentIndex].moveNext()) {
return true;
}
}
return false; // 所有迭代器结束
}
}
class FeedCollection implements Iterable<FeedContent> {
final List<Post> posts;
final List<Ad> ads;
final Stream<Message> messages;
FeedCollection({required this.posts, required this.ads, required this.messages});
Iterator<FeedContent> get iterator => FeedIterator(
posts: posts,
ads: ads,
messages: messages,
);
}
class FeedView extends StatefulWidget {
final FeedCollection feedCollection;
_FeedViewState createState() => _FeedViewState();
}
class _FeedViewState extends State<FeedView> {
final List<Widget> _feedWidgets = [];
void initState() {
super.initState();
_loadFeed();
}
Future<void> _loadFeed() async {
for (final content in widget.feedCollection) {
if (content.isAsync) {
// 异步内容稍后加载
content.buildWidget().then((widget) {
setState(() => _feedWidgets.add(widget));
});
} else {
// 同步内容立即添加
setState(() => _feedWidgets.add(content.buildWidget()));
}
}
}
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _feedWidgets.length,
itemBuilder: (ctx, index) => _feedWidgets[index],
);
}
}
// 树节点迭代器
class TreeNodeIterator implements Iterator<TreeNode> {
final List<TreeNode> _stack = [];
TreeNodeIterator(TreeNode root) {
_stack.add(root);
}
TreeNode get current => _stack.last;
bool moveNext() {
if (_stack.isEmpty) return false;
final node = _stack.removeLast();
// 逆序添加子节点,保证正序访问
for (int i = node.children.length - 1; i >= 0; i--) {
_stack.add(node.children[i]);
}
return _stack.isNotEmpty;
}
}
// 在折叠菜单中使用
ExpandableListView(
iterator: TreeNodeIterator(categoryTree),
builder: (node) => ListTile(
title: Text(node.name),
onTap: () => _handleCategorySelect(node),
),
)
// 分页迭代器
class PaginatedIterator<T> implements Iterator<T> {
final Future<List<T>> Function(int page) _fetchPage;
List<T> _currentItems = [];
int _currentIndex = 0;
int _currentPage = 0;
bool _hasMore = true;
T get current => _currentItems[_currentIndex];
Future<bool> moveNext() async {
_currentIndex++;
// 需要加载下一页
if (_currentIndex >= _currentItems.length && _hasMore) {
final newItems = await _fetchPage(_currentPage + 1);
if (newItems.isEmpty) {
_hasMore = false;
return false;
}
_currentItems.addAll(newItems);
_currentPage++;
}
return _currentIndex < _currentItems.length;
}
}
// 使用
final iterator = PaginatedIterator<Post>((page) => api.fetchPosts(page));
while (await iterator.moveNext()) {
final post = iterator.current;
// 处理帖子...
}
// 图形迭代器
class ShapeIterator implements Iterator<Shape> {
final List<Shape> _shapes;
int _index = 0;
Shape get current => _shapes[_index];
bool moveNext() => ++_index < _shapes.length;
}
// 在CustomPainter中使用
void paint(Canvas canvas, Size size) {
final iterator = ShapeIterator(complexShape.components);
while (iterator.moveNext()) {
final shape = iterator.current;
shape.paint(canvas);
}
}
将分页迭代器与Provider结合:
class PaginatedListProvider extends ChangeNotifier {
final PaginatedIterator<Post> _iterator;
final List<Post> _posts = [];
bool _isLoading = false;
PaginatedListProvider(this._iterator);
Future<void> loadMore() async {
if (_isLoading) return;
_isLoading = true;
notifyListeners();
while (await _iterator.moveNext()) {
_posts.add(_iterator.current);
if (_posts.length % 20 == 0) break; // 每页20条
}
_isLoading = false;
notifyListeners();
}
}
// 在ListView中使用
Consumer<PaginatedListProvider>(
builder: (context, provider, child) {
return ListView.builder(
itemCount: provider._posts.length + (provider._isLoading ? 1 : 0),
itemBuilder: (ctx, index) {
if (index == provider._posts.length) {
provider.loadMore();
return LoadingIndicator();
}
return PostItem(provider._posts[index]);
},
);
}
)
何时使用迭代器模式:
Dart语言特性利用:
// 实现Iterable接口
class MyCollection implements Iterable<Item> {
Iterator<Item> get iterator => MyIterator();
// 支持for-in循环
// 支持map/where/expand等集合操作
}
// 使用yield实现懒加载
Iterable<Item> getItems() sync* {
while (hasMore) {
final batch = fetchNextBatch();
for (final item in batch) {
yield item; // 逐个产出,避免一次性加载
}
}
}
性能优化技巧:
// 懒加载迭代器
class LazyIterator implements Iterator<Item> {
Future<List<Item>>? _currentBatch;
List<Item> _currentItems = [];
int _index = 0;
Future<bool> moveNext() async {
_index++;
if (_index >= _currentItems.length) {
_currentBatch ??= _fetchNextBatch();
_currentItems = await _currentBatch!;
_currentBatch = null;
_index = 0;
}
return _index < _currentItems.length;
}
}
测试策略:
test('树形迭代器应深度优先遍历', () {
final root = buildTestTree();
final iterator = TreeNodeIterator(root);
final visitedOrder = [];
while (iterator.moveNext()) {
visitedOrder.add(iterator.current.id);
}
expect(visitedOrder, equals([1, 2, 3, 4, 5])); // 验证遍历顺序
});
特性 | 迭代器模式 | 访问者模式 |
---|---|---|
目的 | 遍历集合元素 | 对集合元素执行操作 |
焦点 | 如何遍历 | 对元素做什么操作 |
适用场景 | 统一遍历接口/懒加载 | 添加新操作而不修改元素类 |
Flutter应用 | 分页加载/复杂结构遍历 | 报表生成/UI渲染器 |
class FilteringIterator<T> implements Iterator<T> {
final Iterator<T> _source;
final bool Function(T) _predicate;
T? _current;
FilteringIterator(this._source, this._predicate);
T get current => _current!;
bool moveNext() {
while (_source.moveNext()) {
if (_predicate(_source.current)) {
_current = _source.current;
return true;
}
}
return false;
}
}
// 使用
final numbers = [1, 2, 3, 4, 5].iterator;
final evenNumbers = FilteringIterator(numbers, (n) => n % 2 == 0);
class ParallelIterator<T> implements Iterator<T> {
final List<Iterator<T>> _iterators;
int _currentIterator = 0;
T get current => _iterators[_currentIterator].current;
bool moveNext() {
if (_iterators[_currentIterator].moveNext()) {
return true;
}
_currentIterator++;
return _currentIterator < _iterators.length
? _iterators[_currentIterator].moveNext()
: false;
}
}
class FibonacciIterator implements Iterator<int> {
int _a = 0, _b = 1;
int get current => _a;
bool moveNext() {
final next = _a + _b;
_a = _b;
_b = next;
return true; // 无限序列总是返回true
}
}
// 使用
final fib = FibonacciIterator();
for (var i = 0; i < 10; i++) {
fib.moveNext();
print(fib.current); // 0, 1, 1, 2, 3, 5...
}
总结:迭代器模式是你的集合导航仪
设计启示: 当你需要以不同方式"浏览"数据集时,迭代器模式就是你的"导航按钮",让数据流动尽在掌控!