明天我们引见的设计形式叫做命令形式(command),在这个形式下,我们可以完成do和undo的解耦,让运用方不用关心外部的完成细节。
command形式
这个形式我们在日常当中常常运用,举一个很复杂的例子,比如说我们发布代码。发布了之后发现不小心发布上去了一个bug,这个时分我们应该做什么?很复杂,就是回滚,把线上的代码回滚到这一次发布之前的代码。这样我们这次发布带来的改动就会被消弭,那么就避免了bug的产生。
那么,关于一个发布系统来说,它需求做什么?其实也就是两个功用,一个是发布另外一个是回滚。这两个操作是相互可逆的,关于它的运用者来说,是不会关心它的外部是如何完成的,我们只需求在页面上按按钮就好了。
我们来回忆一下这个进程,我们点击发布,可以把最新的代码发布上线。发布之后发现成绩,再点击回滚,系统再自动恢复到发布之前的形状。发布和回滚彼此是可逆的,当我们消弭掉bug之后,再次点击发布,又可以再次发布最新的代码了。
command形式就是做的这个事情,也就是对do和undo的封装。我们来看一个很复杂的例子,对文件改名。比如说我们要把系统当中的文件改名,从A.txt改成B.txt。这个功用很复杂,系统为我们提供了现成的函数,叫做os.rename(),我们只需求把A和B两个文件的地址传入其中即可。
假设我们发现改名字改错了,想回滚怎样办呢?会发现我们改动之前的名字曾经忘了,不知道怎样回滚了。这个时分就可以运用command形式,我们来看代码:
import os
class MoveFileCommand:
def __init__(self, src, dest):
self.src = src
self.dest = dest
def execute(self):
self.rename(self.src, self.dest)
def undo(self):
self.rename(self.dest, self.src)
def rename(self, src, dest):
print('renaming from {} to {}'.format(src, dest))
os.rename(src, dest)
在execute办法当中,我们把文件从src变成了dest,假设想要回滚,它又会再次调用rename。将文件名从dest回滚到src。这样的话,作为运用方就可以完全不用了解api外部的完成逻辑了,不然的话为了避免改错了的状况,还需求做很多适配。
menu item
有了command形式之后我们可以在外面在封装一层用来ui交互上,我们很常见的一种UI交互方式就是按钮。某一个按钮点一下之后会出现一个按过的标记,并且完成一个什么功用。再按一次标记消逝,功用也随之封锁。
我随意找了一个例子,比如下图菜单当中的show minimap,show breadcrumbs这些都是这样的功用。点一下出现缩略图,再点一下缩略图消逝。
假设你写过UI页面的话,普通来说我们会先定义一个Menu Item的类,表示菜单当中的一切的item的基类。不同的选项表示不同的item,我们进一步剖析会发现有些item我们需求这样双击封锁的机制,而有些item是没有的。比如下面的Run、Output这些item都是点一次执行一次的。
我们当然可以把下面引见的Command对象直接当做item,但是这样不利于整个菜单的一致,所以我们还会在外面包一层。比如一切MenuItem的父类应该是这样的:
class MenuItemBaseClass:
def __init__(self):
pass
def pressed(self):
pass
def unpress(self):
pass
有了这个基类之后,我们就可以完成一个可回滚的类,将command的对象作为类成员变量,再在其中完成unpress办法:
class RedoableMenu(MenuItemBaseClass):
def __init__(self, command):
self_command = command
def pressed(self):
self._command.execute()
def unpress(self):
self._command.undo()
(责任编辑:admin)