Flutter数据处理与功能封装插件functional_data的使用
Flutter数据处理与功能封装插件functional_data的使用
functional_data
是一个简单的、非侵入式的代码生成器,用于为数据类型生成样板代码。该包为每个类生成一个简单的mixin,其中包含 operator==
、hashCode
、copyWith
、toString
以及lenses。
Boiler plate(样板代码)
由于样板代码是作为一个mixin生成的,因此对类的接口影响最小。你只需要提供一个带有所有字段命名参数的构造函数,并扩展生成的mixin即可。
@FunctionalData()
class Person extends _$Person {
final String name;
final int age;
const Person({this.name, this.age});
const Person.anonymous() : this(name: "John Doe", age: null);
int get ageInDays => 356 * age;
}
这种设计使你完全控制类。例如,你可以像平时一样添加命名构造函数或方法。
使用
要使用 functional_data
,请将以下依赖项添加到你的包中:
dependencies:
functional_data:
dev_dependencies:
build_runner:
functional_data_generator:
然后运行 flutter packages pub run build_runner build lib
来生成代码。
Lenses(透镜)
对于每个类,都会为所有字段生成透镜,允许查看字段或创建具有某种方式修改的字段的新实例。例如,Person
的 name
的透镜是 Person$.name
。要将透镜聚焦于特定实例,请使用其 of
方法:
final teacher = Person(name: "Arthur", age: 53);
print(Person$.name.of(teacher).value);
// -> "Arthur"
print(Person$.age.of(teacher).update(60));
// -> Person(name: "Arthur", age: 60)
print(Person$.name.of(teacher).map((name) => name.toUpperCase()));
// -> Person(name: "ARTHUR", age: 53)
当组合透镜时,它的强大之处就显现出来了。它允许你轻松地创建一个大型嵌套数据结构的副本,并修改其中一个叶节点的字段。两个透镜可以使用 then
进行链式调用。
class Course extends _$Course {
final String name;
final List<Person> students;
const Course({this.students});
}
final programming = Course(
name: "Programming 101",
students: [
Person(name: "Jane", age: 21),
Person(name: "Tom", age: 20)
]
);
final firstStudentsName = Course$.students.then(List$.first<Person>()).then(Person$.name);
print(firstStudentsName.of(programming).update("Marcy"));
// -> Course(students: [Person(name: "Marcy", age: 21), Person(name: "Tom", age: 20)])
相比之下,不使用透镜的方式如下:
final firstStudent = programming.students.first;
final updatedFirstStudent = Person(name: "Marcy", age: firstStudent.age);
final updatedStudents = [updatedFirstStudent] + programming.students.skip(1);
final updatedCourse = Course(name: programming.name, students: updatedStudents);
这种方式更难以阅读且容易出错。想象一下当其中一个类增加了一个字段时会发生什么。
完整示例
// lens.dart
import 'package:collection/collection.dart';
import 'package:functional_data/functional_data.dart';
part 'lens.g.dart';
@FunctionalData()
class Foo extends _$Foo {
final int number;
final String name;
const Foo({this.number, this.name});
}
@FunctionalData()
class Bar extends _$Bar {
final Foo foo;
@CustomEquality(DeepCollectionEquality())
final List<Foo> foos;
final String driver;
const Bar({this.foo, this.foos, this.driver});
}
void main() {
final foo = Foo(number: 42, name: "Marvin");
final bar = Bar(
foo: foo,
foos: [
Foo(number: 101, name: "One"),
Foo(number: 102, name: "Two")
],
driver: "One"
);
final fooName = Bar$.foo.then(Foo$.name);
print(fooName.of(bar).map((name) => name.toUpperCase()));
// Bar(foo: Foo(number: 42, name: MARVIN), foos: [Foo(number: 101, name: One), Foo(number: 102, name: Two)], driver: One)
final firstFooName = Bar$.foos.then(List$.atIndex<Foo>(0)).then(Foo$.name);
print(firstFooName.of(bar).update("Twee"));
// Bar(foo: Foo(number: 42, name: Marvin), foos: [Foo(number: 101, name: Twee), Foo(number: 102, name: Two)], driver: One)
final nameOfFooNamedTwo = Bar$.foos.then(List$.where<Foo>((foo) => foo.name == "Two")).then(Foo$.name);
print(nameOfFooNamedTwo.update(bar, "Due"));
// Bar(foo: Foo(number: 42, name: Marvin), foos: [Foo(number: 101, name: One), Foo(number: 102, name: Due)], driver: One)
final driversNumber = Bar$.foos.thenWithContext((bar) => List$.where<Foo>((foo) => foo.name == bar.driver).then(Foo$.number));
print(driversNumber.of(bar).value);
// 101
}
代码生成配置
类级别配置
可以通过向 @FunctionalData
发送参数来指定应为类生成哪些功能。
@FunctionalData(
generateCopy: false,
generateLenses: false,
)
class Foo extends _$Foo {}
项目级别配置
可以通过在项目的根目录下创建一个名为 functional_data_options.yaml
的文件来指定应为整个项目生成哪些功能。类级别的参数将覆盖项目级别的配置。
generateCopyWith: false
generateCopyUsing: false
generateLenses: false
通过这些配置,你可以灵活地控制生成的代码,以满足项目的需求。
更多关于Flutter数据处理与功能封装插件functional_data的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据处理与功能封装插件functional_data的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter项目中,使用functional_data
插件可以简化数据处理和功能封装。尽管这个插件可能不是官方库的一部分,但假设它是一个自定义或第三方库,其设计目的通常是为了更好地组织和管理数据逻辑。以下是一个示例,展示如何在Flutter项目中使用假设的functional_data
插件进行数据处理和功能封装。
首先,确保你已经在pubspec.yaml
文件中添加了functional_data
依赖:
dependencies:
flutter:
sdk: flutter
functional_data: ^x.y.z # 替换为实际版本号
然后运行flutter pub get
来安装依赖。
接下来,让我们编写一些代码来演示如何使用这个插件。假设functional_data
提供了一些用于数据处理和封装的实用函数或类。
1. 定义数据模型
假设我们有一个简单的用户数据模型:
// models/user.dart
import 'package:functional_data/functional_data.dart'; // 假设这是插件的导入路径
class User extends Equatable {
final String id;
final String name;
final int age;
User({required this.id, required this.name, required this.age});
@override
List<Object?> get props => [id, name, age];
}
2. 使用functional_data进行数据处理
假设functional_data
提供了一个DataProcessor
类,用于处理数据逻辑。下面是如何使用它的一个示例:
// utils/data_processor.dart
import 'package:functional_data/functional_data.dart'; // 假设这是插件的导入路径
import 'models/user.dart';
class UserDataProcessor {
// 假设DataProcessor是functional_data提供的一个类
final DataProcessor<User> processor = DataProcessor<User>();
// 示例:获取用户列表并应用一些转换
List<User> fetchAndProcessUsers() {
// 模拟从API获取用户数据
List<Map<String, dynamic>> rawUsers = [
{'id': '1', 'name': 'Alice', 'age': 30},
{'id': '2', 'name': 'Bob', 'age': 25},
];
// 使用DataProcessor的map函数转换数据
return processor.map(rawUsers, (raw) {
return User(
id: raw['id']!,
name: raw['name']!,
age: raw['age']!,
);
});
}
}
3. 在UI中使用处理后的数据
最后,我们在Flutter的UI组件中使用这些处理后的数据:
// pages/user_list.dart
import 'package:flutter/material.dart';
import 'utils/data_processor.dart';
import 'models/user.dart';
class UserListPage extends StatefulWidget {
@override
_UserListPageState createState() => _UserListPageState();
}
class _UserListPageState extends State<UserListPage> {
late List<User> users;
final UserDataProcessor processor = UserDataProcessor();
@override
void initState() {
super.initState();
users = processor.fetchAndProcessUsers();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('User List'),
),
body: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
User user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text('Age: ${user.age}'),
);
},
),
);
}
}
在这个示例中,我们:
- 定义了一个用户数据模型
User
。 - 使用
functional_data
提供的DataProcessor
类(假设存在)来处理用户数据。 - 在Flutter的UI组件
UserListPage
中显示处理后的用户列表。
请注意,上述代码是基于假设的functional_data
插件的功能和API设计的。实际使用时,你需要根据functional_data
插件的文档和API来调整代码。如果functional_data
插件的API与上述示例不同,请参考其官方文档进行实现。