先来给大家报个道,上周有事,停更了数天,今天复更。
先来复习一下观察者模式:
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象(主题)和观察者之间的一种一对多的依赖关系,当主题的状态发生改变时,所有依赖于它的观察者都会得到通知并自动更新。
观察者模式主要包含以下几个角色:
-
主题(Subject):它是被观察的对象。它通常维护一个观察者列表,用于存放所有关注自己的观察者对象。当主题的状态发生改变时,主题会遍历观察者列表,通知所有的观察者。
-
观察者(Observer):它定义了一个更新接口,该接口用于在得到主题的改变通知时更新自己。
-
具体主题(Concrete Subject):它是实现了主题接口的具体类,包含一些状态,并在状态发生改变时通知所有的观察者。
-
具体观察者(Concrete Observer):它是实现了观察者接口的具体类,它维护一个指向具体主题的引用,用于获取具体主题的状态。
观察者模式在实际开发中使用广泛,在 GUI 开发中,当用户的操作(如点击按钮)改变了某个对象的状态时,需要通知并更新其他相关的组件,就可以使用观察者模式。
在 Flutter 中,你可以使用 Stream 和 StreamBuilder 来实现观察者模式,其中 Stream 相当于主题,StreamBuilder 相当于观察者。当你向 Stream 中添加数据时,所有的 StreamBuilder 都会得到通知并自动更新 UI。
本文将介绍如何在 Flutter 中使用Provider与自定义实现观察者模式,以处理组件间的状态管理和通信。我们将通过一个具体的例子来演示这个过程:购物车数量更新。在这个例子中,当关注的状态(购物车数量)发生变化时,所有订阅了这个状态的页面都会自动进行更新。
在Flutter中,观察者模式(Observer Pattern)可以用于实现组件间的状态管理和通信。通过观察者模式,当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并进行相应的更新操作
示例:
购物车数量更新 假设我们正在开发一个电子商务应用,其中有一个商品详情页面和一个购物车页面。当用户在商品详情页面点击“加入购物车”按钮时,购物车中的商品数量需要实时更新。
- 需求描述:
- 商品详情页面上有一个"加入购物车"按钮。
- 购物车页面需要实时显示当前购物车中的商品数量。
- 开发实现:
- 创建一个全局的购物车数量状态类(例如
CartCount),用于保存购物车中商品的数量。 - 在商品详情页面中,当用户点击"加入购物车"按钮时,通过调用购物车数量状态类的方法来增加商品数量。
- 在购物车页面中,使用观察者模式来监听购物车数量状态类的变化,一旦数量发生改变,购物车页面会实时更新显示。
- 创建一个全局的购物车数量状态类(例如
使用Provider来实现:
ChangeNotifier 是 Flutter 提供的一个简单的观察者模式实现。我们可以创建一个扩展 ChangeNotifier 的类来保存状态,然后在状态变化时调用 notifyListeners 方法。Consumer 组件可以监听 ChangeNotifier,并在状态变化时自动重建。
我们可以创建一个 CartModel 类来保存购物车的数量,并提供一个方法来增加数量。当数量增加时,我们调用 notifyListeners 来通知所有的 Consumer:
class CartModel extends ChangeNotifier {
int _counter = 0;
int get counter => _counter;
void increment() {
_counter++;
notifyListeners();
}
}
然后,我们可以在商品详情页面中使用 CartModel 来增加数量:
class ProductDetailPage extends StatelessWidget {
final CartModel cartModel;
ProductDetailPage({Key? key, required this.cartModel}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Product Detail'),
),
body: Center(
child: ElevatedButton(
child: Text('Add to cart'),
onPressed: () => cartModel.increment(),
),
),
);
}
}
在购物车页面中,我们使用 Consumer 来监听 CartModel,并显示当前的数量:
class CartPage extends StatelessWidget {
final CartModel cartModel;
CartPage({Key? key, required this.cartModel}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Cart'),
),
body: Center(
child: Consumer<CartModel>(
builder: (context, cart, child) {
return Text('Cart Count: ${cart.counter}');
},
),
),
);
}
}
最后,我们在 main 函数中创建 CartModel 的实例,并使用 ChangeNotifierProvider 来为我们的应用提供这个实例:
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CartModel(),
child: MaterialApp(
home: Builder(
builder: (context) => ProductDetailPage(
cartModel: Provider.of<CartModel>(context, listen: false),
),
),
routes: {
'/cart': (context) => CartPage(
cartModel: Provider.of<CartModel>(context),
),
},
),
),
);
}
如何在不使用任何内置的状态管理机制,如 InheritedWidget、Provider 等,创建自己的观察者模式。
首先,我们定义观察者和被观察者的接口:
抽象的 Observer 类和 Observable 类。Observer 类包含一个 update 方法, Observable 包含 addObserver、removeObserver 和 notifyObservers 方法。
abstract class Observer {
void update();
}
abstract class Observable {
final List<Observer> _observers = [];
void addObserver(Observer observer) {
_observers.add(observer);
}
void removeObserver(Observer observer) {
_observers.remove(observer);
}
void notifyObservers() {
for (final observer in _observers) {
observer.update();
}
}
}
接下来,创建一个 CartModel 类,它实现了 Observable 接口:
class CartModel extends Observable {
int _counter = 0;
int get counter => _counter;
void increment() {
_counter++; notifyObservers();
}
}
CartPage 类,它实现了 Observer 接口:
class CartPage extends StatefulWidget {
final CartModel cartModel;
CartPage({Key? key, required this.cartModel}) : super(key: key);
@override
_CartPageState createState() => _CartPageState();
}
class _CartPageState extends State<CartPage> implements Observer {
@override
void initState() {
super.initState();
widget.cartModel.addObserver(this);
}
@override
void dispose() {
widget.cartModel.removeObserver(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Cart'),
),
body: Center(
child: Text('Cart Count: ${widget.cartModel.counter}'),
),
);
}
@override
void update() {
setState(() {});
}
}
class ProductDetailPage extends StatelessWidget {
final CartModel cartModel;
ProductDetailPage({Key? key, required this.cartModel}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Product Detail'),
),
body: Center(
child: ElevatedButton(
child: Text('Add to cart'),
onPressed: () => cartModel.increment(),
),
),
);
}
}
在 main 函数中,创建 CartModel 的实例,并传递给 CartPage:
void main() {
final cartModel = CartModel();
runApp(
MaterialApp(
home: ProductDetailPage(cartModel: cartModel),
routes: {
'/cart': (context) => CartPage(cartModel: cartModel),
},
),
);
}
在最后这个例子没有使用任何内置的状态管理机制,完全依靠自定义的观察者模式实现状态管理。
使用两种不同的方法演示了同一个需求的实现,包括一个商品详情页和一个购物车页。在商品详情页中,可以通过点击按钮来增加购物车数量,然后在购物车页中查看当前购物车数量。
通过此例,我们可以看到观察者模式在处理状态管理和组件间通信时的优势。使用观察者模式,我们能够实现状态的封装,保证了数据的一致性,同时也提高了代码的可维护性和可复用性。
然而,手动实现观察者模式需要编写大量的模板代码,且在处理更复杂的状态管理和通信需求时,可能会变得非常复杂。因此,在实际的开发中,通常会使用一些现有的状态管理库,如 Provider、Riverpod、Mobx 等,这些库提供了更高级的功能和工具,可以更方便地实现观察者模式和状态管理。
希望对您有所帮助谢谢!!!