背景
在使用 Flutter 开发跨平台应用时,我们发现现有应用的逻辑代码和视图代码没有充分解耦。这在开发多端(如iOS、Android、Mac、Windows、Web)场景下,不利于复用已编写的逻辑,从而影响开发效率。我们可以利用 Mixin 的能力解决这个问题
目标
在不影响现有功能的基础上,重构应用的业务代码。通过复用重构后的逻辑代码,快速完成 APP 端的功能迁移到桌面端,提高代码的一致性、扩展性,并适配多端场景。
解决方案
移动端应用(APP)
对现有代码进行改造:
- 将APP页面中的
State
抽离,封装成StateMixin
(StateMixin:继承于 State 的 mixin); - 保留APP页面的UI代码,将封装好的
StateMixin
进行混入
,以还原业务实现;
其他平台
通过复用封装的 StateMixin
,采用 View+StateMixin
的方式实现业务,从而实现逻辑层的跨平台复用:
- 将多端共用的属性和方法提取并封装成基类(BaseState),统一处理可复用的业务逻辑;
- 将各端差异化的属性和方法提取并封装成子类(如AppState、DesktopState、WebState),以个性化处理各端差异化的业务。
StateMixin
classDiagram
BaseState <|-- AppState
BaseState <|-- DesktopState
BaseState <|-- WebState
BaseState : String name
BaseState : int age
BaseState: initState()
BaseState: eat()
class AppState{
String height
@override initState()
run()
}
class DesktopState{
String width
@override initState()
jump()
}
class WebState{
@override
String name
@override initState()
dance()
}
mixin BaseState<T extends BaseView> on State<T> {}
mixin AppState<T extends AppView> on BaseState<T> {}
mixin DesktopState<T extends DesktopView> on BaseState<T> {}
mixin WebState<T extends WebView> on BaseState<T> {}
Widget
classDiagram
BaseView <|-- AppView
BaseView <|-- DesktopView
BaseView <|-- WebView
BaseView : String viewName
class AppView{ }
class DesktopView{ }
class WebView{ }
class BaseView extends StatefulWidget {}
class AppView extends BaseView {}
class _AppViewState extends State<AppView> with BaseState, AppState {}
class DesktopView extends BaseView {}
class _DesktopViewState extends State<DesktopView> with BaseState, DesktopState {}
class WebView extends WebView {}
class _WebViewState extends State<WebView> with BaseState, WebState {}
优势
- 最小化对现有代码的修改;
- 充分解耦各平台代码;
- 通过子类覆盖父类方法,灵活应对各种业务场景;
对现有 APP 代码的改动较小,只需将 State 中的属性和方法迁移至 mixin 文件,保留 widget 视图代码。然后将 mixin 文件重新混入视图代码中,即可完成 APP 代码的重构。其他平台可直接复用 mixin。对于 APP 中原有的方法名、属性名和逻辑,基本无需调整。
注意事项
- 抽离至mixin中的属性或方法不能设为
私有
(正确示例:name;错误示例:_name)- 混入mixin时,
基类必须放在子类前面
(示例:State<AppView> with BaseState, AppState
)- 可以通过基础视图类
BaseView
处理页面间传参
具体实施
view 实现
- 通过适配层动态渲染 APP 和 桌面端 UI视图
- 通过 mixin 实现逻辑复用
// index.dart
Widget build(BuildContext context) {
// 通过视图适配层,收敛多端视图的适配
return AdapterLayout(
mobile: AppGroupShareView(todoLabel: widget.todoLabel,),
desktop: DesktopGroupShareView(todoLabel: widget.todoLabel),
);
}
// base_group_share_view.dart
abstract class BaseGroupShareView extends StatefulWidget {
const BaseGroupShareView({Key? key, required this.todoLabel})
: super(key: key);
final TodoLabel todoLabel;
}
// app_group_share_view.dart
class AppGroupShareView extends BaseGroupShareView {
AppGroupShareView({Key? key, required todoLabel})
: super(todoLabel: todoLabel);
@override
_AppGroupShareViewState createState() => _AppGroupShareViewState();
}
class _AppGroupShareViewState extends State<AppGroupShareView>
with BaseGroupShareMethod, AppGroupShareMethod {}
// desktop_group_share_view.dart
class DesktopGroupShareView extends BaseGroupShareView {
const DesktopGroupShareView({Key? key, required todoLabel})
: super(todoLabel: todoLabel);
@override
_DesktopGroupShareViewState createState() => _DesktopGroupShareViewState();
}
class _DesktopGroupShareViewState extends State<DesktopGroupShareView>
with BaseGroupShareMethod, DesktopGroupShareMethod {}
mixin 实现
// base_group_share_method.dart
mixin BaseGroupShareMethod<T extends BaseGroupShareView> on State<T> {
get isCreate {
// 业务逻辑
reture 1
}
void initState() {
super.initState();
// 业务逻辑
// ...
}
// 可直接使用
void backGroupShare() {
resetLabel();
}
// 需子类实现
void jumpToContactView() {}
// 需子类实现
void refreshUI() {}
}
// app_group_share_method.dart
mixin AppGroupShareMethod<T extends AppGroupShareView>
on BaseGroupShareMethod<T> {
void backGroupShare() {
// 调用父类方法
super.backGroupShare();
Get.back();
}
// 重新方法,各端差异实现
void jumpToContactView() {
Get.to(() => Contact());
}
// 刷新UI
refreshUI() {
TDStore().todoLabelsStore.fetchServerData().then((value) {
// ...
});
}
}
// desktop_group_share.method
mixin DesktopGroupShareMethod<T extends DesktopGroupShareView>
on BaseGroupShareMethod<T> {
// 重新方法,各端差异实现
void jumpToContactView() {
print('跳转桌面端');
}
}
总结
在本文中,我们提供了一种 Flutter 实现多端应用开发中逻辑层的复用与解耦的方案。通过对现有代码的改造和封装,我们能够在最小化对现有代码的修改的同时,充分解耦各平台代码,并灵活应对各种业务场景。希望对大家有所帮助!