回顾Dart - 为什么在Dart中很少用到面向协议开发?
前言
在Swift
开发中,我们推崇面向协议开发,并通过扩展(extension)和默认实现来提供灵活的行为复用,提升代码的可维护性和可扩展性。
为什么推崇面向协议开发?
- 解耦代码:协议将具体实现与接口分离,减少模块之间的依赖性,提高代码的可测试性和可维护性。
- 提高灵活性:协议可以让类型更加灵活,因为不同的类型可以遵循同一个协议,从而提供多态性。
- 提升复用性:通过协议和扩展,可以复用代码而不必依赖继承,避免了继承层次过深的问题。
- 增强可读性:协议提供了明确的行为描述,使代码更容易理解和维护。
Dart中的面向协议开发
Abstract Class
概念
abstract
类是无法被实例化的类。它可以包含抽象方法(没有方法体的方法)和具体方法(有方法体的方法)。抽象类通常用于定义通用的接口或基础行为,然后由子类实现具体的行为。
使用场景
用于定义通用的接口或基础行为,然后由子类实现具体的行为。
示例
abstract class AnimalAbstract {
void eat();
void sleep() {
debugPrint("sleep");
}
}
class Dog extends AnimalAbstract {
@override
void eat() {
// TODO: implement eat
}
}
Implements
概念
implements
关键字用于让一个类实现一个或多个接口。接口在 Dart 中实际上就是普通的类,但是当一个类使用 implements
关键字实现接口时,它必须实现接口中所有的方法。
使用场景
用于确保一个类实现特定的接口方法和属性,通常用于定义和强制实现某种协议或契约。
示例
class AnimalImp {
void eat() {}
void sleep() {}
}
class Cat implements AnimalImp {
@override
void eat() {
// TODO: implement eat
}
@override
void sleep() {
// TODO: implement sleep
}
}
class Duck implements AnimalImp {
@override
void eat() {
// TODO: implement eat
}
@override
void sleep() {
// TODO: implement sleep
}
}
Mixin
概念
mixin
是一种在多个类之间重用代码的方法。一个 mixin
类通常只包含方法的实现,而不包含状态(实例变量)。可以在一个类中使用多个 mixin
,从而实现代码重用。
使用场景
用于在多个类之间重用代码,提供一种机制来避免多重继承的问题。
示例
mixin Fly {
void toFly() {
debugPrint("can fly");
}
}
mixin Swimming {
void toSwimming() {
debugPrint("can swimming");
}
}
class Duck with Fly, Swimming {
void test() {
toFly();
toSwimming();
}
}
为什么在flutter开发中,不常使用这些特性
在 Flutter 开发中,虽然 Dart 提供了 abstract
类、implements
关键字和 mixin
这些特性,但它们的使用频率相对较低。这主要是因为 Flutter 框架和 Dart 语言本身的一些设计和惯例。以下是一些原因和解释:
Flutter 的 Widget 架构
Flutter 的核心是其声明式 UI 架构,Widget 是其构建块。Flutter 的设计鼓励使用组合(composition)而不是继承(inheritance)来构建 UI 组件。这意味着开发者更倾向于通过将多个小部件组合在一起来创建复杂的 UI,而不是通过继承和抽象来实现。
class MyCustomWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Hello, World!'),
Icon(Icons.star),
],
);
}
}
在这个例子中,我们通过组合 Text
和 Icon
组件来构建一个自定义的小部件,而不是通过继承和抽象。
简单和易于理解
组合(composition)比继承(inheritance)更容易理解和维护。继承层次过深会使得代码复杂且难以维护,而组合可以避免这种问题。Flutter 强调简单和直观的代码结构,这使得开发者更倾向于使用组合。
Mixins 在特定场景下使用
虽然 mixin 是 Dart 提供的一个强大特性,但它主要用于在多个类之间重用代码。在 Flutter 中,mixin 通常用于提供额外的功能或行为,而不是核心的 UI 组件。例如,Flutter 中的 SingleTickerProviderStateMixin
就是一个常用的 mixin,用于在 State
对象中管理动画控制器。
class MyAnimatedWidgetState extends State<MyAnimatedWidget> with SingleTickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container();
}
}
Implements 的限制
在 Flutter 中,implements
关键字用于强制一个类实现特定的接口。这在需要确保类具有某些方法时非常有用,但在实际使用中,它可能会导致大量的样板代码(boilerplate code),因为必须实现接口中所有的方法。Flutter 的设计更倾向于使用已有的 Widget 组合来实现功能,而不是定义大量接口。
Abstract 类的使用场景
抽象类在 Flutter 中主要用于定义一些通用的接口或行为,然后由具体的子类来实现。虽然有时会使用抽象类来定义一些基础功能,但在 Flutter 的 UI 组件设计中,这种情况相对较少。更多时候,我们会看到一些通用的接口或基础类用于非 UI 逻辑,如数据处理或服务类。
abstract class DataService {
Future<void> fetchData();
}
class ApiDataService implements DataService {
@override
Future<void> fetchData() async {
// 实现 API 数据获取逻辑
}
}
总结
虽然 Dart 提供了丰富的面向对象特性,但在 Flutter 开发中,由于其声明式 UI 架构和组合优先的设计理念,这些特性的使用频率相对较低。Flutter 更倾向于通过组合和现成的 Widget 来构建 UI,而不是通过复杂的继承层次和接口实现。这使得 Flutter 的代码更加直观和易于维护。
转载自:https://juejin.cn/post/7379446193141088283