Appearance
第13章:Dart 模块化与库(工程化基础)
13.1 模块化概述
什么是模块化?
模块化是将代码按照功能或逻辑划分为多个独立的模块,每个模块负责特定的功能。模块化可以提高代码的可维护性、可重用性和可读性。
模块化的优点
- 代码复用:可以在多个项目中重用模块
- 可维护性:模块之间相互独立,修改一个模块不会影响其他模块
- 可读性:代码结构清晰,便于理解和调试
- 并行开发:多个开发者可以同时开发不同的模块
Dart 中的模块化
在 Dart 中,模块化主要通过库(library)来实现。每个 Dart 文件默认都是一个库,也可以通过 library 关键字显式声明一个库。
13.2 库的导入与使用
导入系统库
Dart 提供了一些内置的系统库,如 dart:core、dart:io、dart:async 等。这些库可以直接导入使用。
dart
import 'dart:core'; // 导入核心库
import 'dart:io'; // 导入输入输出库
import 'dart:async'; // 导入异步库导入自定义库
可以导入自己创建的库文件,使用相对路径或绝对路径。
dart
// 导入同一目录下的库
import 'utils.dart';
// 导入子目录下的库
import 'models/user.dart';
// 导入父目录下的库
import '../helpers/date.dart';导入第三方库
可以从 pub.dev 仓库导入第三方库,需要在 pubspec.yaml 文件中声明依赖,然后使用 pub get 命令安装。
yaml
# pubspec.yaml
dependencies:
http: ^1.0.0
flutter:
sdk: flutterdart
// 导入第三方库
import 'package:http/http.dart' as http;13.3 库的导出
导出单个库
可以使用 export 关键字导出一个库,使得其他文件可以通过导入这个库来访问被导出的库。
dart
// utils.dart
export 'math_utils.dart';
export 'string_utils.dart';
export 'date_utils.dart';导出部分内容
可以使用 show 或 hide 关键字来控制导出的内容。
dart
// utils.dart
export 'math_utils.dart' show add, subtract;
// 只导出 math_utils.dart 中的 add 和 subtract 函数
export 'string_utils.dart' hide capitalize;
// 导出 string_utils.dart 中除了 capitalize 以外的所有内容13.4 命名空间
使用 as 关键字
当导入的库中有同名的函数或类时,可以使用 as 关键字为库指定一个前缀,避免命名冲突。
dart
import 'package:http/http.dart' as http;
import 'package:xml/xml.dart' as xml;
void main() {
// 使用 http 前缀访问 http 库中的函数
var response = await http.get(Uri.parse('https://example.com'));
// 使用 xml 前缀访问 xml 库中的函数
var document = xml.XmlDocument.parse(response.body);
}导入部分内容
可以使用 show 或 hide 关键字来控制导入的内容,减少命名冲突的可能性。
dart
// 只导入 math_utils.dart 中的 add 和 subtract 函数
import 'math_utils.dart' show add, subtract;
// 导入 string_utils.dart 中除了 capitalize 以外的所有内容
import 'string_utils.dart' hide capitalize;13.5 实操案例
拆分代码为多个模块
1. 创建工具类模块
dart
// utils/math_utils.dart
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int multiply(int a, int b) {
return a * b;
}
double divide(int a, int b) {
if (b == 0) {
throw ArgumentError('Division by zero');
}
return a / b;
}dart
// utils/string_utils.dart
String capitalize(String str) {
if (str.isEmpty) return str;
return str[0].toUpperCase() + str.substring(1);
}
String reverse(String str) {
return str.split('').reversed.join();
}
bool isPalindrome(String str) {
return str == reverse(str);
}2. 创建导出文件
dart
// utils/utils.dart
export 'math_utils.dart';
export 'string_utils.dart';3. 在主文件中使用
dart
// main.dart
import 'utils/utils.dart';
void main() {
// 使用 math_utils.dart 中的函数
print('1 + 2 = ${add(1, 2)}');
print('5 - 3 = ${subtract(5, 3)}');
print('2 * 4 = ${multiply(2, 4)}');
print('10 / 2 = ${divide(10, 2)}');
// 使用 string_utils.dart 中的函数
print('Capitalize: ${capitalize('hello')}');
print('Reverse: ${reverse('hello')}');
print('Is palindrome "level": ${isPalindrome('level')}');
print('Is palindrome "hello": ${isPalindrome('hello')}');
}实现库的导入与导出
1. 创建模型类
dart
// models/user.dart
class User {
final String id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
@override
String toString() {
return 'User(id: $id, name: $name, email: $email)';
}
}dart
// models/product.dart
class Product {
final String id;
final String name;
final double price;
Product({required this.id, required this.name, required this.price});
@override
String toString() {
return 'Product(id: $id, name: $name, price: $price)';
}
}2. 创建导出文件
dart
// models/models.dart
export 'user.dart';
export 'product.dart';3. 创建服务类
dart
// services/api_service.dart
import 'dart:convert';
import 'dart:io';
import '../models/models.dart';
class ApiService {
final HttpClient _client = HttpClient();
Future<List<User>> getUsers() async {
var url = Uri.parse('https://jsonplaceholder.typicode.com/users');
var request = await _client.getUrl(url);
var response = await request.close();
if (response.statusCode != HttpStatus.ok) {
throw Exception('Failed to get users');
}
var responseBody = await response.transform(utf8.decoder).join();
var jsonList = jsonDecode(responseBody) as List;
return jsonList.map((json) => User(
id: json['id'].toString(),
name: json['name'],
email: json['email'],
)).toList();
}
Future<List<Product>> getProducts() async {
var url = Uri.parse('https://fakestoreapi.com/products');
var request = await _client.getUrl(url);
var response = await request.close();
if (response.statusCode != HttpStatus.ok) {
throw Exception('Failed to get products');
}
var responseBody = await response.transform(utf8.decoder).join();
var jsonList = jsonDecode(responseBody) as List;
return jsonList.map((json) => Product(
id: json['id'].toString(),
name: json['title'],
price: json['price'].toDouble(),
)).toList();
}
void close() {
_client.close();
}
}4. 在主文件中使用
dart
// main.dart
import 'services/api_service.dart';
void main() async {
var apiService = ApiService();
try {
print('Fetching users...');
var users = await apiService.getUsers();
print('Users: ${users.take(3)}'); // 只打印前3个用户
print('\nFetching products...');
var products = await apiService.getProducts();
print('Products: ${products.take(3)}'); // 只打印前3个产品
} catch (e) {
print('Error: $e');
} finally {
apiService.close();
}
}13.6 模块化最佳实践
1. 合理划分模块
根据功能或逻辑合理划分模块,每个模块负责特定的功能。
2. 保持模块的独立性
模块之间应该保持独立,通过明确的接口进行通信,避免模块之间的紧密耦合。
3. 使用命名空间
使用 as 关键字为库指定前缀,避免命名冲突。
4. 控制导入和导出的内容
使用 show 或 hide 关键字控制导入和导出的内容,减少不必要的依赖。
5. 文档注释
为模块和公共 API 添加文档注释,提高代码的可读性和可维护性。
6. 版本控制
对于第三方库,指定明确的版本范围,避免版本冲突。
小结
- 模块化 是将代码按照功能或逻辑划分为多个独立的模块,提高代码的可维护性、可重用性和可读性。
- 库的导入与使用:可以导入系统库、自定义库和第三方库。
- 库的导出:使用
export关键字导出库,使得其他文件可以通过导入这个库来访问被导出的库。 - 命名空间:使用
as关键字为库指定前缀,避免命名冲突。 - 模块化最佳实践:合理划分模块、保持模块的独立性、使用命名空间、控制导入和导出的内容、添加文档注释、版本控制等。
通过掌握模块化和库的使用,你可以编写更结构化、更可维护的 Dart 代码,提高开发效率。
