跳转到正文
YGJoon 技术博客

Dart 库和可见性详解

发布于:
·1.1k 字 · 约 3 分钟·作者:
下划线实现私有成员、import 别名与按需导入组织模块,配合合理的目录结构,把库拆分与可见性控制一次理顺。
Dart 库和可见性详解文章封面
目录

简介

Dart 中的库机制用于代码组织和重用。通过库,我们可以控制代码的可见性,实现模块化开发。

库的定义

创建库

// lib/my_library.dart
library my_library;

// 导出其他文件
export 'src/utils.dart';
export 'src/models.dart';

// 库级别的变量和函数
const version = '1.0.0';

void doSomething() {
  print('Doing something...');
}

私有成员

class User {
  // 公开成员
  String name;
  
  // 私有成员(以下划线开头)
  String _password;
  
  // 私有构造函数
  User._(this.name, this._password);
  
  // 工厂构造函数
  factory User.create(String name, String password) {
    return User._(name, password);
  }
  
  // 私有方法
  void _validatePassword() {
    // 实现密码验证
  }
}

导入机制

基本导入

// 导入 Dart 核心库
import 'dart:core';
import 'dart:async';

// 导入第三方库
import 'package:http/http.dart';
import 'package:path/path.dart';

// 导入项目内的库
import 'package:my_app/src/utils.dart';

导入别名

// 使用 as 关键字指定别名
import 'package:lib1/lib1.dart' as lib1;
import 'package:lib2/lib2.dart' as lib2;

void main() {
  lib1.someFunction();
  lib2.someFunction();
}

部分导入

// 只导入特定成员
import 'package:lib/lib.dart' show foo, bar;

// 隐藏特定成员
import 'package:lib/lib.dart' hide baz;

库的组织

目录结构

my_package/
  ├── lib/
  │   ├── my_package.dart       # 主库文件
  │   └── src/                  # 私有实现
  │       ├── utils.dart
  │       └── models.dart
  ├── test/                     # 测试文件
  └── pubspec.yaml              # 包配置文件

主库文件

// lib/my_package.dart
library my_package;

// 导出公共 API
export 'src/utils.dart' show Utility, Helper;
export 'src/models.dart';

完整示例

// lib/src/models.dart
part of '../my_package.dart';

class User {
  final String id;
  final String name;
  final String _token;
  
  User._(this.id, this.name, this._token);
  
  factory User.create(String name) {
    final id = DateTime.now().toString();
    final token = _generateToken();
    return User._(id, name, token);
  }
  
  static String _generateToken() {
    // 实现token生成
    return DateTime.now().toString();
  }
}

// lib/src/utils.dart
part of '../my_package.dart';

class ApiClient {
  final String _baseUrl;
  final String _apiKey;
  
  ApiClient._(this._baseUrl, this._apiKey);
  
  factory ApiClient.create(String baseUrl, String apiKey) {
    return ApiClient._(baseUrl, apiKey);
  }
  
  Future<Map<String, dynamic>> get(String endpoint) async {
    // 实现 GET 请求
    return {};
  }
  
  Future<Map<String, dynamic>> post(
    String endpoint,
    Map<String, dynamic> data,
  ) async {
    // 实现 POST 请求
    return {};
  }
}

// lib/my_package.dart
library my_package;

import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;

part 'src/models.dart';
part 'src/utils.dart';

// 公共 API
class MyPackage {
  static final instance = MyPackage._();
  
  final ApiClient _apiClient;
  
  MyPackage._()
      : _apiClient = ApiClient.create(
          'https://api.example.com',
          'your-api-key',
        );
  
  Future<User> createUser(String name) async {
    final response = await _apiClient.post(
      '/users',
      {'name': name},
    );
    
    return User.create(name);
  }
}

最佳实践

  1. 合理组织库结构
  2. 明确公共 API
  3. 使用 part 和 part of
  4. 控制可见性范围
  5. 提供清晰的文档

注意事项

  1. 避免循环依赖
  2. 合理使用私有成员
  3. 注意库的版本兼容
  4. 控制导出的 API
  5. 遵循命名规范

实战案例:下划线就是我的访问控制

Dart 没有 private/public 关键字——以下划线开头的就是库私有。这个设计我一开始很不习惯(Java 写多了),直到在 ygking_json_to_dart_model 里尝到甜头:

// lib/services/json_converter.dart
class JsonConverter {
  String convertJsonToDart(String jsonStr, String className) { ... }  // 公开:唯一入口

  void _generateClass(Map<String, dynamic> map, ...) { ... }  // 私有:递归实现细节
  String _getFieldType(dynamic value, String key) { ... }     // 私有:类型推导
}

调用方 import 这个库之后,只能看到 convertJsonToDart。_generateClass 的 4 个参数、_getFieldType 的推导规则,全是实现细节——下划线就是文档,告诉别人”这个别碰,改了我不负责”。

但下划线有个容易忽略的点:它的作用域是”库”(library)不是”类”。同一个文件里的另一个类,可以直接访问 _generateClass——因为它们在同一个库里。Dart 里”一个文件就是一个库”(除非用 part 拆分)。所以我的做法是:json_converter.dart 一个文件只放 JsonConverter 这一个类,私有方法天然就是”类私有”的效果。

对比 flutter_brightness 的 SerialService:_port、_reader、_controller、_isConnected 全是下划线私有字段,对外只暴露 dataStream、isConnected 和 connect()。如果 _isConnected 是公开的,UI 层手滑把它设成 true,串口明明没连上,界面却显示”已连接”——这种状态不一致的 bug,靠”默认私有”在编译期就掐死了。

总结

Dart 的库机制提供了强大的代码组织和可见性控制能力。通过合理使用库机制,可以构建出结构清晰、易于维护的代码库。理解并掌握库的使用对于开发大型 Dart 应用很有帮助。


分享这篇文章:


相关文章

上一篇
Dart 错误处理详解
下一篇
Dart 泛型详解