Flutter访客管理插件visitor的使用

Flutter访客管理插件visitor的使用

visitor 插件简介

visitor 是一个基于 Dart 的库,它可以根据类和类型定义上的注解生成代码,这些代码实现了访问者模式(Visitor Pattern)。通过这种方式,可以方便地处理具有复杂结构的对象树。

例如,在一个 func.dart 文件中,你可以定义如下代码:

import 'package:visitor/visitor.dart';

part 'func.g.dart';

@Visitor(name: "Func")
class _Func<R> {}

@VisitorBranch(of: _Func)
typedef _Func$Supplier<T, R> = T Function();

@VisitorBranch(of: _Func)
typedef _Func$UnaryOperator<T, R> = T Function(R x);

@VisitorBranch(of: _Func)
typedef _Func$BinaryOperator<T, R> = T Function(R x, R y);

这将生成如下的代码到 func.g.dart 文件中:

abstract class Func<R> {
  const factory Func.supplier() = _OnSupplierFunc;

  const factory Func.unaryOperator(R x) = _OnUnaryOperatorFunc;

  const factory Func.binaryOperator(R x, R y) = _OnBinaryOperatorFunc;

  const Func._();

  T choose<T>({
    required _Func$Supplier<T, R> onSupplier,
    required _Func$UnaryOperator<T, R> onUnaryOperator,
    required _Func$BinaryOperator<T, R> onBinaryOperator,
  });
}

class _OnSupplierFunc<R> extends Func<R> {
  const _OnSupplierFunc() : super._();

  @override
  T choose<T>({
    required _Func$Supplier<T, R> onSupplier,
    required _Func$UnaryOperator<T, R> onUnaryOperator,
    required _Func$BinaryOperator<T, R> onBinaryOperator,
  }) {
    return onSupplier();
  }
}

class _OnUnaryOperatorFunc<R> extends Func<R> {
  final R x;

  const _OnUnaryOperatorFunc(this.x) : super._();

  @override
  T choose<T>({
    required _Func$Supplier<T, R> onSupplier,
    required _Func$UnaryOperator<T, R> onUnaryOperator,
    required _Func$BinaryOperator<T, R> onBinaryOperator,
  }) {
    return onUnaryOperator(x);
  }
}

class _OnBinaryOperatorFunc<R> extends Func<R> {
  final R x;
  final R y;

  const _OnBinaryOperatorFunc(this.x, this.y) : super._();

  @override
  T choose<T>({
    required _Func$Supplier<T, R> onSupplier,
    required _Func$UnaryOperator<T, R> onUnaryOperator,
    required _Func$BinaryOperator<T, R> onBinaryOperator,
  }) {
    return onBinaryOperator(x, y);
  }
}

你可以在以下代码中使用生成的代码:

int apply(Func<int> func) {
  final int result = func.choose<int>(
    onSupplier: () => 1,
    onUnaryOperator: (x) => 2 * x,
    onBinaryOperator: (x, y) => x + y,
  );
  return result;
}

void main() {
  Func<int> f;

  f = Func.supplier();
  print(apply(f));
  // 输出: 1

  f = Func.unaryOperator(2);
  print(apply(f));
  // 输出: 4

  f = Func.binaryOperator(3, 5);
  print(apply(f));
  // 输出: 8
}

或者,你可以将其视为类似于 Kotlin 中密封类的概念。

特性

  • 支持泛型。
  • 支持递归参数类型。
  • 支持命名参数和可选参数。

开始使用

在你的 pubspec.yaml 文件中添加此依赖作为开发依赖项。

使用方法

该库导出了两个注解:VisitorVisitorBranch

Visitor 注解

Visitor 注解用于类。类名必须以一个或多个下划线开头(例如 _Example)。

@Visitor()
class _Example {}

VisitorBranch 注解

VisitorBranch 注解用于类型定义(typedef)。它接收一个必需的参数 of,应为它的访问者类型。

@VisitorBranch(of: _Example)

每个带有 VisitorBranch 注解的 typedef 将成为其相应访问者的分支,并且:

  • 必须别名为一个函数,该函数可以有零个或多个参数;
  • 必须有一个返回类型 T 的参数类型;
  • 可以有任意名称,但建议以 _$ 开头,以避免外部引用。如果有多个访问者在一个文件中声明,则为了避免名称冲突,其名称应为 _ + 访问者的大写驼峰命名法名称 + $ + 分支的大写驼峰命名法名称。
@VisitorBranch(of: _Example)
typedef _$FirstBranch<T> = T Function(int);

在当前文件的导入部分下方添加一个部分声明。例如,如果文件名为 file.dart

part 'file.g.dart';

在添加了 Visitor、其 VisitorBranch 和部分声明之后,在项目的根目录下运行以下命令:

dart run build_runner build

# 或者,如果你正在使用 Flutter
flutter pub run build_runner build

生成的代码将被添加到部分声明中描述的文件中。以下是更改的内容:

  • 生成访问者的名称将是类名去掉第一个下划线(例如 Example)。
  • 访问者中的生成工厂方法的名称将是每个分支的小写驼峰命名法(例如 firstBranch)。
  • 访问者的生成子类的名称将是每个分支的大写驼峰命名法,前缀为 _On 并后缀于大写驼峰命名法的访问者名称(例如 _OnFirstBranchExample)。
  • 访问者的回调名称将是每个分支的大写驼峰命名法,前缀为 on(例如 onFirstBranch)。
abstract class Example implements _Example {
  const factory Example.firstBranch(int p0) = _OnFirstBranchExample;

  const Example._();

  T choose<T>({
    required T Function(int) onFirstBranch,
  });
}

class _OnFirstBranchExample extends Example {
  final int p0;

  const _OnFirstBranchExample(int p0) : super._();

  T choose<T>({
    required T Function(int) onFirstBranch,
  }) {
    return onFirstBranch(p0);
  }
}

对于带有 VisitorBranch 注解的 typedef,linter 可能会产生一个未使用的元素警告。为了避免这种情况,可以在文件顶部添加以下内容:

// ignore_for_file: unused_element

示例

你可以在 example/lib/visitor_example.dart 文件中看到用法。

example/lib/examples 中:

  • expression.dart 显示了递归参数类型的用法;
  • diff_change.dart 显示了命名参数的用法;
  • loading_state.dart 显示了泛型的用法。

示例代码

以下是一个完整的示例代码:

import 'package:visitor_example/examples/diff_change.dart';
import 'package:visitor_example/examples/expression.dart';
import 'package:visitor_example/examples/loading_state.dart';

void runExpressionExample() {
  int evaluate(Expression expression) {
    return expression.choose(
      onConstant: (v) => v,
      onSum: (e0, e1) => evaluate(e0) + evaluate(e1),
      onZero: () => 0,
    );
  }

  print(evaluate(loadExpression("21 + 0 + 4")));
  // 输出: 25
}

void runDiffChangeExample() {
  final List<DiffChange> changes = loadChanges(
    ["area", "beer", null, "city", null, "edge"],
    ["acid", "beer", null, null, "deep", "else"],
  );
  for (DiffChange change in changes) {
    print(change.choose<String>(
      onAdded: (v) => "+ $v",
      onDeleted: (v) => "- $v",
      onUnchanged: (v) => "  $v",
      onChanged: ({required v0, required v1}) => "* $v1 (was $v0)",
    ));
  }
  // 输出:
  // * acid (was area)
  //   beer
  // - city
  // + deep
  // * else (was edge)
}

Future<void> runLoadingStateExample() async {
  final Stream<LoadingState> stream = loadStates();
  await for (LoadingState state in stream) {
    print(state.choose(
      onWaiting: () => "waiting",
      onError: (e) => "error ($e)",
      onValue: (v) => "value ($v)",
      onDone: () => "done",
    ));
  }
  // 输出:
  // waiting
  // value (1)
  // value (2)
  // error (Bad state: i == 3)
  // value (4)
  // value (5)
  // done
}

void main() async {
  runExpressionExample();
  runDiffChangeExample();
  await runLoadingStateExample();
}

更多关于Flutter访客管理插件visitor的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

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


在 Flutter 中使用 visitor 插件进行访客管理,通常是指一个用于管理访客信息的插件。假设 visitor 插件是一个用于记录和管理访客信息的库,以下是如何使用它的基本步骤。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 visitor 插件的依赖。

dependencies:
  flutter:
    sdk: flutter
  visitor: ^1.0.0  # 请根据实际版本号进行替换

然后运行 flutter pub get 来获取依赖。

2. 导入插件

在你的 Dart 文件中导入 visitor 插件。

import 'package:visitor/visitor.dart';

3. 初始化插件

在使用插件之前,通常需要对其进行初始化。你可以在 main.dart 文件中进行初始化。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Visitor.initialize();  // 假设插件提供了初始化方法
  runApp(MyApp());
}

4. 记录访客信息

你可以使用插件提供的方法来记录访客信息。例如:

void recordVisitor() {
  Visitor.record(
    name: 'John Doe',
    phone: '123-456-7890',
    email: 'john.doe@example.com',
    purpose: 'Meeting',
    time: DateTime.now(),
  );
}

5. 获取访客列表

你可以使用插件提供的方法来获取访客列表。例如:

Future<void> getVisitors() async {
  List<Visitor> visitors = await Visitor.getVisitors();
  visitors.forEach((visitor) {
    print('Name: ${visitor.name}, Purpose: ${visitor.purpose}');
  });
}

6. 删除访客记录

你可以使用插件提供的方法来删除访客记录。例如:

void deleteVisitor(String visitorId) {
  Visitor.delete(visitorId);
}

7. 更新访客记录

你可以使用插件提供的方法来更新访客记录。例如:

void updateVisitor(String visitorId, String newPurpose) {
  Visitor.update(
    visitorId: visitorId,
    purpose: newPurpose,
  );
}

8. 在 UI 中使用

你可以在 Flutter 的 UI 中使用这些方法来显示和管理访客信息。例如:

class VisitorList extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return FutureBuilder<List<Visitor>>(
      future: Visitor.getVisitors(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return CircularProgressIndicator();
        } else if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}');
        } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
          return Text('No visitors found');
        } else {
          return ListView.builder(
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              var visitor = snapshot.data![index];
              return ListTile(
                title: Text(visitor.name),
                subtitle: Text(visitor.purpose),
                trailing: IconButton(
                  icon: Icon(Icons.delete),
                  onPressed: () => deleteVisitor(visitor.id),
                ),
              );
            },
          );
        }
      },
    );
  }
}
回到顶部