命令模式
问题:
如果页面必须处理很多不同的任务,就应该考虑将任务进行封装。封装之后,向系统中增加新任务就会变得简单,并且可以将系统中的各部分分离开来。这时,我们就可以使用命令模式了。
概念:
将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
实现:
1. 类图示例:
2. 代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | //命令对象参数类 class CommandContext { private $params = []; private $error = '' ; public function __construct() { $this ->params = $_REQUEST ; } public function addParam( $key , $val ) { $this ->params[ $key ] = $val ; } public function get( $key ) { return $this ->params[ $key ]; } public function setError( $error ) { $this ->error = $error ; } public function getError() { return $this ->error; } } //命令对象基类 abstract class Command { abstract public function execute(CommandContext $context ); } //命令对象具体实现 class LoginCommand extends Command { public function execute(CommandContext $context ) { $manager = Registry::getAccessManager(); $user = $context ->get( 'username' ); $pass = $context ->get( 'pass' ); $userObj = $manager ->login( $user , $pass ); if ( is_null ( $userObj )) { $context ->setError( $manager ->getError()); return false; } $context ->addParam( 'user' , $userObj ); return true; } } //命令对象具体实现 class FeedbackCommand extends Command { public function execute(CommandContext $context ) { $msgSystem = Registry::getMessageSystem(); $email = $context ->get( 'email' ); $msg = $context ->get( 'msg' ); $topic = $context ->get( 'topic' ); $result = $msgSystem ->send( $email , $msg , $topic ); if (! $result ) { $context ->setError( $msgSystem ->getError()); return false; } return true; } } //命令对象异常类 class CommandNotFoundException extends Exception {} //命令对象工厂类 class CommandFactory { private static $dir = 'commands' ; public static function getCommand( $action = 'default' ) { if (preg_match( '/\W/' , $action )) { throw new Exception( 'illegal characters in action' ); } $class = ucfirst( strtolower ( $action )) . 'Command' ; $file = self:: $dir . DIRECTORY_SEPARATOR . $class . '.php' ; if (! file_exists ( $file )) { throw new CommandNotFoundException( 'file not found: ' . $file ); } require_once ( $file ); if (! class_exists ( $class )) { throw new CommandNotFoundException( 'class not found: ' . $file ); } $cmd = new $class (); return $cmd ; } } //命令对象调用者 class Controller { private $context ; public function __construct() { $this ->context = new CommandContext(); } public function getContext() { return $this ->context; } public function process() { $cmd = CommandFactory::getCommand( $this ->context->get( 'action' )); if (! $cmd ->execute( $this ->context)) { //失败处理 } else { //成功 } } } //伪造用户请求测试 $controller = new Controller(); $context = $controller ->getContext(); $context ->addParam( 'action' , 'login' ); $context ->addParam( 'username' , 'jet' ); $context ->addParam( 'pass' , '888888' ); $controller ->process(); |
注意:Command对象不应该执行太多的逻辑。它们应该负责检查输入、处理错误、缓存对象和调用其他对象来执行一些必要的操作。
效果:
1. 能比较容易地设计一个命令队列。
2. 在需要的情况下,可以较容易地将命令记入日志。
3. 允许接收请求的一方决定是否要否决请求。
4. 可以很容易地实现对请求的撤销和重做。
5. 由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易。
6. 促进了控制器和领域模型的分离。
7. 更好地组织系统,易于扩展。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)