【设计模式 13】命令:覆水能收

【设计模式 13】命令:覆水能收 这一课讲命令模式。什么在变决策需要记录、排队、撤销。怎么挡把决策封装成命令对象可执行可回滚。林衍那次决策失误后来集团内部管它叫黑色十月。起因是赵闯带回来一条消息一家新晋竞争对手拿到了十亿级融资开始用补贴战打市场。对方的核心策略简单粗暴——同品质产品低于成本价销售靠融资的钱烧出市场份额。林衍在战略会上拍板应战。全线产品降价百分之二十抢在对手前面把价格打到底。陈敏当时就反对“百分之二十你知道这意味着什么吗全年毛利率从百分之三十二降到百分之十四。如果我们抢不到足够的市场份额来弥补这一年的利润就白干了。”林衍说“战争打的是速度。先抢份额利润明年追回来。”赵闯全力执行。降价通知发给了全部经销商终端价格更新到所有渠道电商页面同步改价返点方案重新计算。整个集团像一台机器一样用了四十八小时完成了全面降价。两周后数据出来了。陈敏把报表放在林衍桌上没说话。林衍看了五分钟。销量增长了百分之十一。不是百分之三十不是百分之五十。百分之十一。利润呢少了十九亿。更糟的是竞争对手根本没跟降。他们拿了融资不假但补贴战的消息是赵闯从行业饭局上听来的二手情报。对方拿了钱是用来建产线、做研发的不是用来烧补贴的。赵闯的情报错了。林衍基于错误情报做了决策。而决策已经执行了两周不可逆转。林衍找陈敏“能撤回吗”陈敏看着他像在看一个问能不能把倒出去的水收回来的人。“价格已经通知了全部经销商。终端价格已经改了。返点已经结算了一期。你现在涨回去经销商觉得你在玩他们。不涨回去十九亿已经没了。”林衍那天晚上一个人在办公室坐到凌晨两点。第二天早上林衍叫了一个会。不是复盘会——复盘以后再做。他要的是一件更根本的东西。“如果下次我做了一个决策执行了一半发现是错的我能不能撤回”陈敏说“那要看决策执行到了哪一步。如果只是内部通知可以撤。如果已经到了终端撤不了。”“如果到了终端但是刚到呢比如只执行了一天”“理论上可以改回来。但你要知道改回来需要做哪些事——通知经销商、改价格、调返点、更新页面——跟执行决策的时候一样反过来做一遍。”林衍在白板上写了一行字每一个重大决策执行前必须封装成可撤销的操作。“什么叫封装成可撤销的操作”林衍说“就是每一次决策不是’直接执行’而是变成一个指令。指令包含三样东西执行动作、撤销动作、执行记录。执行的时候做’执行动作’撤回的时候做’撤销动作’。不管决策涉及到多少个部门、多少个系统撤回就是调一下’撤销’。”陈敏问“那如果执行了一半呢比如经销商已经收到通知了但终端还没改价”“指令要记录执行到哪一步了。撤回的时候从当前步骤往回退。不是一刀切回原点是逐步回滚。”林衍在白板上写的那个制度——每一个决策封装成可撤销的指令——在程序设计里有一个名字命令模式。把做什么封装成一个命令对象调用方只持有命令。命令可以排队、存储、撤销。覆水能收。stores history«interface»Commandexecute()undo()PricingDecision-amount: float-receiver: BusinessUnitexecute()undo()ExpansionDecision-region: string-receiver: BusinessUnitexecute()undo()DecisionLog-history: Command[]submitCommand(cmd: Command)undoLast()BusinessUnitapplyPriceChange(amount)revertPriceChange(amount)applyExpansion(region)revertExpansion(region)林衍的决策日志就是 DecisionLog每一条定价或扩张指令都是一个 Command错了就调 undo 回滚。孙子说先为不可胜以待敌之可胜。“先让自己处于不会输的位置再等赢的机会。命令模式做的就是先让自己不会输”——每一个决策都带着退路错了能撤不至于一错到底。本文所有人物、情节、公司名均为虚构如有雷同纯属巧合。