Flutter开发实战:命令模式(Command Patte

命令模式(Command Pattern)是一种设计模式,它在面向对象编程中封装了方法调用或特定的操作。这种模式把请求封装为对象,从而让你可以使用不同的请求、队列,或者请求的参数化来参数化其他对象。同时,它也支持撤销操作。

这种模式通常包含以下四种元素:

  1. 命令(Command):这是执行实际操作的接口。它定义了一个或多个方法,这些方法定义了如何执行请求。

  2. 具体命令(ConcreteCommand):实现命令接口的类。这个类通常包含一些特定的数据,并覆盖了接口中定义的方法,以执行特定的命令。

  3. 请求者(Invoker):这个类负责调用命令。它通常包含一个或多个命令对象,并定义了当命令应该被执行的条件。

  4. 接收者(Receiver):这是命令的最终执行者。它知道如何执行与命令相关的操作。

下面我们通过两个示例来模拟在Flutter中如何使用命令模式(Command Pattern)

场景一:音乐播放器控制

开发一个音乐播放器应用。可以通过点击播放、暂停、上一首和下一首按钮来控制音乐播放。在这种情况下,可以使用命令模式,把每个按钮的操作封装成一个命令。

  • 接收者(Receiver) 是音乐播放器,它知道如何播放、暂停、切换到上一首或下一首音乐。
  • 具体命令(ConcreteCommand) 是播放、暂停、上一首和下一首操作。
  • 请求者(Invoker) 是各个按钮,它们调用对应的命令。
import 'package:flutter/material.dart';

// Receiver: 知道如何执行具体的操作
class MusicPlayer {
  void play() {
    print('Playing music');
  }

  void pause() {
    print('Music paused');
  }

  void next() {
    print('Switch to next music');
  }

  void prev() {
    print('Switch to previous music');
  }
}

// Command interface: 定义了命令的接口
abstract class MusicCommand {
  void execute();
}

// ConcreteCommands: 具体的命令,它们封装了接收者的操作

class PlayCommand implements MusicCommand {
  MusicPlayer player;
  PlayCommand(this.player); // 初始化时将接收者传入

  @override
  void execute() {
    player.play(); // 执行接收者的play操作
  }
}

class PauseCommand implements MusicCommand {
  MusicPlayer player;
  PauseCommand(this.player); // 初始化时将接收者传入

  @override
  void execute() {
    player.pause(); // 执行接收者的pause操作
  }
}

class NextCommand implements MusicCommand {
  MusicPlayer player;
  NextCommand(this.player); // 初始化时将接收者传入

  @override
  void execute() {
    player.next(); // 执行接收者的next操作
  }
}

class PrevCommand implements MusicCommand {
  MusicPlayer player;
  PrevCommand(this.player); // 初始化时将接收者传入

  @override
  void execute() {
    player.prev(); // 执行接收者的prev操作
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
    MyApp({Key? key}) : super(key: key);
  final MusicPlayer musicPlayer = MusicPlayer(); // 创建接收者

  @override
  Widget build(BuildContext context) {
    // Invokers: 请求者,它们调用命令的execute方法来执行操作
    var playButton = ElevatedButton(
      child: Text('Play'),
      onPressed: PlayCommand(musicPlayer).execute, // 创建并执行PlayCommand
    );
    var pauseButton = ElevatedButton(
      child: Text('Pause'),
      onPressed: PauseCommand(musicPlayer).execute, // 创建并执行PauseCommand
    );
    var nextButton = ElevatedButton(
      child: Text('Next'),
      onPressed: NextCommand(musicPlayer).execute, // 创建并执行NextCommand
    );
    var prevButton = ElevatedButton(
      child: Text('Prev'),
      onPressed: PrevCommand(musicPlayer).execute, // 创建并执行PrevCommand
    );

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Music Player'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              playButton,
              pauseButton,
              nextButton,
              prevButton,
            ],
          ),
        ),
      ),
    );
  }
}

MusicPlayer是接收者,它知道如何执行具体的操作。PlayCommandPauseCommandNextCommandPrevCommand是具体命令,它们封装了接收者的操作。FlatButton是请求者,它们调用命令的execute方法来执行操作。

场景二:任务队列管理

模拟一个任务队列的场景。假设有一个任务队列,可以将新的任务添加到队列中,然后按照它们被添加到队列中的顺序依次执行这些任务。

将任务封装为命令对象,每个命令对象都知道如何执行自己。当需要执行一个任务时,从队列中取出一个命令对象,然后执行它。

  • 接收者(Receiver) 是任务执行者,它知道如何执行任务。
  • 具体命令(ConcreteCommand) 是各种任务,它们被封装在命令对象中。
  • 请求者(Invoker) 是任务队列,它维护了一个命令对象的列表,并按照顺序执行这些命令。
import 'package:flutter/material.dart';

// Receiver: 任务执行者
class TaskExecutor {
  void executeTask(String task) {
    print('Executing task: $task');
  }
}

// Command interface: 定义了命令的接口
abstract class TaskCommand {
  void execute();
}

// ConcreteCommand: 具体的命令,它封装了任务和执行任务的方法
class Task implements TaskCommand {
  TaskExecutor executor; // 接收者实例
  String task; // 任务内容

  Task(this.executor, this.task); // 初始化时将接收者和任务内容传入

  @override
  void execute() {
    executor.executeTask(task); // 调用接收者的方法来执行任务
  }
}

// Invoker: 请求者,它维护了一个命令对象的列表,并按照顺序执行这些命令
class TaskQueue {
  List<Task> tasks = [];

  void addTask(Task task) {
    tasks.add(task); // 添加任务到队列
  }

  void executeAll() {
    tasks.forEach((task) {
      task.execute(); // 执行每一个任务
    });

    tasks.clear(); // 清空队列
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);
  final TaskExecutor executor = TaskExecutor(); // 创建接收者实例
  final TaskQueue queue = TaskQueue(); // 创建请求者实例

  @override
  Widget build(BuildContext context) {
    var task1 = Task(executor, 'Task 1'); // 创建任务1
    var task2 = Task(executor, 'Task 2'); // 创建任务2
    var task3 = Task(executor, 'Task 3'); // 创建任务3

    queue.addTask(task1); // 将任务1添加到队列
    queue.addTask(task2); // 将任务2添加到队列
    queue.addTask(task3); // 将任务3添加到队列

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Task Queue'),
        ),
        body: Center(
          child: ElevatedButton(
            child: Text('Execute All Tasks'),
            onPressed: queue.executeAll, // 点击按钮时执行队列中的所有任务
          ),
        ),
      ),
    );
  }
}

TaskExecutor是接收者,它知道如何执行任务。Task是具体的命令,它封装了一个任务和执行这个任务的方法。TaskQueue是请求者,维护了一个命令对象的列表,并按照顺序执行这些命令。

命令模式是一种常用的设计模式,它将请求封装成对象,以便使用不同的请求、队列或者请求的参数化来参数化其他对象。命令模式同时也支持撤销操作。它包含四个主要组成部分:接收者(Receiver)、命令(Command)、具体命令(ConcreteCommand)和请求者(Invoker)。

在Flutter中使用了命令模式来解决两个具体的问题:音乐播放器控制和任务队列管理。

在音乐播放器控制的案例中,接收者是音乐播放器,它具备播放、暂停、切换音乐等能力;具体命令即为播放、暂停、切换音乐等操作,这些操作被封装在ConcreteCommand中;请求者则为各个控制按钮,它们会触发ConcreteCommand的执行。

在任务队列管理的案例中,接收者是任务执行者,它能够执行特定的任务;具体命令则为各个独立的任务,它们被封装在ConcreteCommand中;请求者是任务队列,它会按照一定的顺序触发ConcreteCommand的执行。

通过这两个案例,我们可以看到命令模式的优点:它能够将请求的发送者和接收者解耦,使得请求的发送者不需要知道接收者的具体操作和执行逻辑,只需要调用ConcreteCommand的execute方法即可。同时,由于每个操作都被封装成了对象,这使得程序更加模块化,也使得添加新操作或者修改现有操作变得更加容易,有利于代码的维护和扩展。

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

全部评论

相关推荐

付费才包邮:本科有这种简历很强了
点赞 评论 收藏
分享
徐新高:号已经废了 建议重开一个账号投简历
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务