Flutter数据模型管理插件modddels的使用

发布于 1周前 作者 gougou168 来自 Flutter

Flutter数据模型管理插件modddels的使用

简介

modddels 是一个强大的代码生成器,允许您创建自验证的数据模型,这些模型具有编译安全的状态、无缝的失败处理和易于单元测试的特点。它解决了在应用中创建和验证数据模型时遇到的一些常见问题,如在哪里进行验证、如何区分有效和无效实例等。

动机

假设您想要建模一个 Student 对象,该对象有姓名、年龄和电子邮件地址。传统上,您可能会像下面这样定义您的类:

class Student {
  Student({
    required this.name,
    required this.age,
    required this.email,
  });

  final String name;
  final int age;
  final String email;
}

然而,这种方法存在一些问题:

  • 在哪里验证 name, age, 和 email
  • 如何区分有效的 Student 实例和无效的实例?
  • 如何确保将有效的 Student 实例传递给需要它们的函数或小部件?

这些问题都可以通过使用 modddels 包来解决。

特性

  • 自我验证:模型在创建时即被验证。
  • 密封类:您的模型是一个密封类,具有不同的状态(有效、无效等)。
  • 失败处理:当模型无效时,它会持有导致失败的原因,您可以随时访问。
  • 值相等性和不可变性:所有模型都是不可变的,并且重写了 operator ==hashCode
  • 单元测试:轻松测试您的模型及其验证逻辑。

示例

以下是一个使用 modddels 的简单示例。完整的例子可以在 GitHub 上找到。

完整示例 Demo

import 'package:example/modddels/age.dart';
import 'package:example/modddels/user.dart';
import 'package:example/modddels/username.dart';

// In this example, [Username], [Age] and [User] are all "modddels".
void main() {
  final username =
      Username('dash_the_bird', availabilityService: MyAvailabilityService());

  final age = Age(20);

  final user = User.appUser(username: username, age: age);

  // Map over the different validation states of the user.
  user.map(
    valid: (valid) => greetUser(valid),
    invalidMid: (invalidMid) => redirectToProfileInfoScreen(invalidMid),
  );
}

// This method can only accept a [ValidUser], i.e a valid instance of [User].
void greetUser(ValidUser user) {
  final username = user.username.value;

  // Map over the different types of users ([AppUser] or [Moderator])
  final greeting = user.mapUser(
      appUser: (validAppUser) => 'Hey $username ! Enjoy our app.',
      moderator: (validModerator) =>
          'Hello $username ! Thanks for being a great moderator.');

  print(greeting);
}

// This method can only accept an [InvalidUserMid], i.e an invalid instance of
// [User] specifically because of a failure in the validationStep named "mid".
void redirectToProfileInfoScreen(InvalidUserMid user) {
  print('Redirecting to profile ...');

  // Checking if the `age` is invalid, and handling the only possible failure.
  user.age.mapOrNull(
    invalidValue: (invalidAgeValue) => invalidAgeValue.legalFailure.map(
      minor: (_) => print('You should be 18 to use our app.'),
    ),
  );

  // Checking if the `username` is invalid, and handling its possible failures.
  user.username.map(
    valid: (validUsername) {},
    invalidValue1: (invalidUsernameValue1) {
      // Handling failures of the "length" validation.
      if (invalidUsernameValue1.hasLengthFailure) {
        final errorMessage = invalidUsernameValue1.lengthFailure!.map(
          empty: (value) => 'Username can\'t be empty.',
          tooShort: (value) =>
              'Username must be at least ${value.minLength} characters long.',
          tooLong: (value) =>
              'Username must be less than ${value.maxLength} characters long.',
        );
        print(errorMessage);
      }

      // Handling failures of the "characters" validation.
      if (invalidUsernameValue1.hasCharactersFailure) {
        final errorMessage = invalidUsernameValue1.charactersFailure!.map(
          hasWhiteSpace: (hasWhiteSpace) =>
              'Username can\'t contain any whitespace character.',
          hasSpecialCharacters: (hasSpecialCharacters) =>
              'Username can only contain letters, numbers and dashes.',
        );
        print(errorMessage);
      }
    },
    invalidValue2: (invalidUsernameValue2) {
      // Handling failures of the "availability" validation. This validation is
      // part of a separate validationStep than the two previous ones for
      // optimization purposes.
      final errorMessage = invalidUsernameValue2.availabilityFailure.map(
        unavailable: (unavailable) => 'Username is already taken.',
      );

      print(errorMessage);
    },
  );
}

更多关于Flutter数据模型管理插件modddels的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据模型管理插件modddels的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,管理数据模型通常涉及创建和管理应用状态,而modddels(假设你指的是类似mobxproviderriverpod等状态管理插件的误写)这样的插件可以帮助你更有效地实现这一点。虽然没有一个确切名为modddels的Flutter插件,但我会展示如何使用provider插件来管理数据模型,因为provider是Flutter社区中非常流行的一个状态管理解决方案。

使用provider插件管理数据模型

首先,确保在你的pubspec.yaml文件中添加了provider依赖:

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0  # 请检查最新版本号

然后,运行flutter pub get来安装依赖。

创建一个数据模型

假设我们有一个简单的用户数据模型:

// models/user.dart
class User {
  final String name;
  final int age;

  User(this.name, this.age);
}

创建一个ChangeNotifier来管理这个模型

我们将使用ChangeNotifier来包装我们的用户数据,这样我们就可以监听它的变化:

// providers/user_provider.dart
import 'package:flutter/material.dart';
import 'models/user.dart';

class UserProvider with ChangeNotifier {
  User _user = User('John Doe', 30);

  User getUser() {
    return _user;
  }

  void setUser(User newUser) {
    _user = newUser;
    notifyListeners();
  }
}

在应用中提供UserProvider

在你的应用入口(通常是main.dart)中,使用MultiProvider来提供UserProvider

// main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'providers/user_provider.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => UserProvider()),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Provider Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: UserScreen(),
    );
  }
}

在UI中消费UserProvider

最后,在你的UI组件中,使用ConsumerProvider.of<T>(context)来访问UserProvider

// screens/user_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/user.dart';
import 'providers/user_provider.dart';

class UserScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('User Info'),
      ),
      body: Center(
        child: Consumer<UserProvider>(
          builder: (context, userProvider, child) {
            User user = userProvider.getUser();
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Name: ${user.name}'),
                Text('Age: ${user.age}'),
                SizedBox(height: 20),
                ElevatedButton(
                  onPressed: () {
                    userProvider.setUser(User('Jane Doe', 25));
                  },
                  child: Text('Update User'),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

以上代码展示了如何使用provider插件来管理一个简单的用户数据模型。你可以根据需要扩展这个模型,添加更多的属性和方法,以及更多的状态管理逻辑。

回到顶部