Flutter开发实战:备忘录模式(Memento Patt

备忘录模式(Memento Pattern)是一种行为设计模式,主要目的是捕获对象的当前内部状态,并提供一种方式在未来的某个时刻恢复这个状态,而不会破坏对象的封装性。这种模式通常用于实现诸如“撤销”、“恢复”和“历史记录”等功能。

备忘录模式的核心概念:

  1. 原发器 (Originator):它是我们希望保存状态的对象。原发器可以创建一个备忘录,里面包含其当前的内部状态。此外,它还可以使用备忘录来恢复其内部状态。

  2. 备忘录 (Memento):备忘录是一个不透明的对象,它存储原发器的内部状态。备忘录有两个接口,一个是为原发器提供的宽接口,另一个是为其他对象提供的窄接口。这确保了除原发器之外的对象不能访问备忘录的内容。

  3. 管理者 (Caretaker):管理者负责保存备忘录,但不应该对备忘录的内容进行任何操作或检查。它只能请求原发器创建备忘录和请求原发器恢复一个备忘录。

备忘录模式.svg

优点:

  • 它提供了一种能够捕获对象的内部状态并在以后恢复它的机制,而不破坏对象的封装性。
  • 它简化了原发器的结构。原发器可以将复杂的状态保存逻辑外部化到备忘录中。

缺点:

  • 如果频繁地保存大量信息,那么备忘录模式可能会占用大量的内存。
  • 管理备忘录可能会增加系统的复杂性。

备忘录模式为那些需要保存和恢复对象状态的应用程序提供了一种结构化的解决方案,同时确保了对象内部的封装性不会被破坏。

场景一:画图应用

一个简单的画图应用,用户可以在屏幕上绘制直线。每次用户绘制一条新的直线,都会保存当前的画布状态。这样,如果用户犯了一个错误,或者不喜欢他们最近的更改,可以使用“撤销”按钮来撤销最后的操作。

  • 原发器 (Originator) : 画布,保存当前的所有线条。
  • 备忘录 (Memento) : 保存在某个特定时间点上的画布状态。
  • 管理者 (Caretaker) : 维护一个历史记录,允许用户撤销和恢复操作。
// === 原发器 (Originator) ===
class OriginatorCanvas {
  List<Line> _lines = [];

  void drawLine(Line line) {
    _lines.add(line);
  }

  CanvasMemento saveState() {
    return CanvasMemento(List.from(_lines));
  }

  void restore(CanvasMemento memento) {
    _lines = memento.lines;
  }
}

class Line {
  Offset start;
  Offset end;
  Line(this.start, this.end);
}

// === 备忘录 (Memento) ===
class CanvasMemento {
  final List<Line> lines;
  CanvasMemento(this.lines);
}

// === 管理者 (Caretaker) ===
class CanvasHistory {
  final List<CanvasMemento> _history = [];

  void add(CanvasMemento memento) {
    _history.add(memento);
  }

  CanvasMemento? undo() {
    if (_history.isEmpty) return null;
    var lastMemento = _history.removeLast();
    return lastMemento;
  }
}

class DrawingCanvas extends StatefulWidget {
  @override
  _DrawingCanvasState createState() => _DrawingCanvasState();
}

class _DrawingCanvasState extends State<DrawingCanvas> {
  final OriginatorCanvas _canvas = OriginatorCanvas();
  final CanvasHistory _canvasHistory = CanvasHistory();
  Line? _currentLine;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Drawing App with Memento'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.undo),
            onPressed: _undo,
          ),
        ],
      ),
      body: GestureDetector(
        onPanStart: (details) {
          setState(() {
            _currentLine = Line(details.localPosition, details.localPosition);
            _canvas.drawLine(_currentLine!);
            _canvasHistory.add(_canvas.saveState());
          });
        },
        onPanUpdate: (details) {
          setState(() {
            _currentLine!.end = details.localPosition;
          });
        },
        onPanEnd: (details) {
          _currentLine = null;
        },
        child: CustomPaint(
          painter: CanvasPainter(_canvas),
          child: Container(),
        ),
      ),
    );
  }

  void _undo() {
    var memento = _canvasHistory.undo();
    if (memento != null) {
      _canvas.restore(memento);
      setState(() {});
    }
  }
}

class CanvasPainter extends CustomPainter {
  final OriginatorCanvas _canvas;

  CanvasPainter(this._canvas);

  @override
  void paint(Canvas canvas, Size size) {
    // Paint all lines from _canvas onto the Flutter canvas
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

void main() => runApp(DrawingApp());

class DrawingApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Drawing App with Memento',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DrawingCanvas(),
    );
  }
}

上面的伪代码描述了一个简单的绘图应用,使用备忘录模式。用户可以在画布上绘制线条,并使用撤销按钮返回到以前的状态。

  1. 原发器 (Originator) - Canvas:

    • 保存当前所有线条的列表。
    • 提供绘制线条的方法。
    • 提供保存和恢复状态的方法。
  2. 备忘录 (Memento) - CanvasMemento:

    • 保存一系列线条,这代表了画布在某一时刻的状态。
  3. 管理者 (Caretaker) - CanvasHistory:

    • 维护一个历史列表,该列表保存了画布的历史状态。
    • 提供添加和撤销方法,以管理这些状态。
  4. UI部分:

    • 一个DrawingCanvas StatefulWidget,它提供了绘图界面和一个撤销按钮。
    • 用户可以通过触摸屏幕来绘制线条。
    • 当用户开始绘制线条时,它将保存当前的画布状态。
    • 用户可以点击撤销按钮来返回到上一个状态。

CanvasPainter中的绘图逻辑需要根据实际需求进行进一步完善。

场景二:电商应用的商品筛选功能

在一个电商应用中,用户可能希望通过多个条件(如价格、品牌、评分等)来筛选商品。在设置筛选条件后,用户可能希望返回上一个筛选状态,撤销最近的筛选条件。

  • 原发器 (Originator): 当前应用的筛选设置。
  • 备忘录 (Memento): 保存应用在某个时间点的筛选设置。
  • 管理者 (Caretaker): 记录用户所有筛选的历史,使他们可以撤销或重做筛选设置。

// === 原发器 (Originator) ===
class FilterSetting {
  double? maxPrice;
  double? minRating;
  List<String> brands = [];

  FilterMemento save() {
    return FilterMemento(maxPrice, minRating, List.from(brands));
  }

  void restore(FilterMemento memento) {
    maxPrice = memento.maxPrice;
    minRating = memento.minRating;
    brands = memento.brands;
  }
}

// === 备忘录 (Memento) ===
class FilterMemento {
  final double? maxPrice;
  final double? minRating;
  final List<String> brands;

  FilterMemento(this.maxPrice, this.minRating, this.brands);
}

// === 管理者 (Caretaker) ===
class FilterHistory {
  final List<FilterMemento> _history = [];

  void add(FilterMemento memento) {
    _history.add(memento);
  }

  FilterMemento? undo() {
    if (_history.isEmpty) return null;
    return _history.removeLast();
  }
}

class _FilterAppState extends State<FilterApp> {
  final FilterSetting _filterSetting = FilterSetting();
  final FilterHistory _filterHistory = FilterHistory();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Product Filter')),
        body: Column(
          children: [
            // ... Some UI components to set the filters ...
            ElevatedButton(
              child: Text('Apply Filters'),
              onPressed: () {
                _filterHistory.add(_filterSetting.save());
                // ... Apply the filters and update the product list ...
                setState(() {});
              },
            ),
            ElevatedButton(
              child: Text('Undo Filter Change'),
              onPressed: () {
                var memento = _filterHistory.undo();
                if (memento != null) {
                  _filterSetting.restore(memento);
                  // ... Reapply the filters based on the restored settings ...
                  setState(() {});
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}


void main() => runApp(FilterApp());

class FilterApp extends StatefulWidget {
  @override
  _FilterAppState createState() => _FilterAppState();
}

用户可以通过各种UI组件(例如滑块、复选框等)设置筛选条件。应用保存每次筛选的状态,因此用户可以轻松撤销上一次的筛选设置。备忘录模式确保了筛选状态的历史被保存,以便在需要时进行恢复。

总结

备忘录模式是一种行为设计模式,允许对象在不暴露其内部结构的前提下保存和恢复其内部状态。这种模式在许多现实世界的应用场景中都有实际应用,特别是在需要提供“撤销”或“恢复”功能的场景中。

画图应用

在画图应用中,用户可以自由地在屏幕上绘制。每当用户添加或修改图形元素时,应用都需要保存当前的状态。这样,如果用户犯了错误或不满意最后的更改,他们可以简单地点击“撤销”按钮,返回到之前的状态。

在这个场景中:

  • 原发器 (Originator) 是画布,它保存了所有的绘图元素。
  • 备忘录 (Memento) 是一个特定时间点的画布状态,包括所有的线条、形状和颜色信息。
  • 管理者 (Caretaker) 是一个历史记录工具,它跟踪用户所做的所有更改,并允许他们回到任何先前的状态。

电商应用的商品筛选功能

在电商平台上,用户通常希望根据特定的条件(如价格范围、品牌或评分)筛选商品。当用户设置筛选条件后,应用保存当前的筛选状态。这样,如果用户想撤销某些筛选条件并返回到之前的搜索结果,可以点击“撤销筛选”按钮。

  • 原发器 (Originator) 是筛选设置,包括所有用户选择的筛选条件。
  • 备忘录 (Memento) 保存了一个特定时间点的筛选设置。
  • 管理者 (Caretaker) 是一个筛选历史工具,它跟踪用户设置的所有筛选条件,并允许回到任何先前的筛选状态。

结论

无论是在画图应用中提供撤销绘图功能,还是在电商平台上提供撤销筛选功能,备忘录模式都是一种非常有用的设计模式。它不仅提供了一种保存对象状态的简洁方式,而且确保了对象内部的封装性不会被破坏。这使得开发者可以轻松地为用户提供强大的功能,同时保持代码的整洁和模块化。

希望对您有所帮助谢谢!!!

全部评论

相关推荐

点赞 评论 收藏
分享
10-28 14:42
门头沟学院 Java
watermelon1124:因为嵌入式炸了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务