一个vim框架的简单实现
vim有编辑器之神的美誉。
有一定的学习曲线,但是熟练之后真是让人爱不熟手啊。vim可以让人完全抛弃鼠标,所有操作全部通过命令实现,大大提高编码的效率。
废话不多说,下面我说一下我的实现:
1. vim3个模式:
一般模式,插入模式,以及命令模式。
一般模式:主要用于进行复制黏贴删除、定位光标等操作。
插入模式:进行编辑代码的模式。
命令模式:也称底行模式(命令会在底行显示)。主要用于打开、保存、关闭文件。
模式之间的切换如下图所示:
2. 设计
2.1 模式类簇
我们知道,不同的模式下有不同的行为。即对于相同的输入,不同的模式应当有不同的响应。不仅如此,模式还需做到模式之间的切换。总结下来,模式应 当实现两大功能:
1. 执行模式下相应的命令。
2. 负责模式之间的切换。
自然地,设计如下:
InsertMode代表:插入模式
EditMode代表:编辑模式
CommandMode代表:命令模式
Mode接口下提供2个方法:
1. public void execute(Object view); 用于执行方法
2. public Modes modesSwitch(String in, Object view); 负责切换模式。注意此方法依旧返回Mode接口。
modesSwitch返回值为Mode接口,若返回其他Mode,则实现模式之间的切换;若返回this,则代表模式并没有更改。
2.2 命令类簇
在插入模式下,主要用于向文本区域插入文本内容;在编辑模式下,主要用于对文本内容进行编辑;在命令模式下,主要用于对文本文件进行保存、新建等 操作。不管在何种模式下,这些操作都是通过键盘输入,通过输入的字符串,各模式对字符串进行解析,得到相应的命令及参数。我们已经有了模式类,那么对 于这些命令,也作一定的封装。
设计如下:
Command:作为所有命令的抽象类。在设计模式中,命令模式便是将其操作对象封装进类中,这里,我们也将view作为命令的操作对象。
ComnComn:作为命令模式下命令的父类。execute方法用于执行命令。
EditComn:作为编辑模式下命令的父类。execute方法用于执行命令。
InsrComn:作为插入模式下命令的父类。该模式主要用于插入字符,暂时并无命令。为扩展方便,此处先将类列出来。
当需要加入命令时,只需继承相应的模式命令类即可。
在这一部分中,我主要实现了以下几个命令:
命令模式:vi-->OpenFile、w-->SaveComn、q-->QuitComn
编辑模式:ndd-->DeleteComn
可以想见,当命令增多时,管理这些命令类也是一个较为头疼的问题。这里,我采用了类工厂方法的方案,之所以是类工厂方法,我做了一定的改良:
每一个模式中的命令类都采用一个hashmap维护。其键为:命令码;其值为:完整类名。
这样做的好处是:可以采用反射,省掉很多的if-else。
代码如下:
1 public class ComnHash { 2 public static Map comnlist = new HashMap<String, String>(); 3 4 static { 5 comnlist.put(":w", "org.wgx.command.comn.SaveComn"); 6 comnlist.put(":q", "org.wgx.command.comn.QuitComn"); 7 comnlist.put(":vi", "org.wgx.command.comn.OpenFile"); 8 } 9 10 public static ComnComn getComn(String comnStr) { 11 if (comnlist.containsKey(comnStr)) { 12 ComnComn cc = null; 13 try { 14 cc = (ComnComn) Class.forName((String)comnlist.get(comnStr)).newInstance(); 15 } catch (InstantiationException | IllegalAccessException 16 | ClassNotFoundException e) { 17 // TODO Auto-generated catch block 18 System.out.println("无此命令啊"); 19 } 20 return cc; 21 } 22 return null; 23 } 24 }
上层代码需要调用命令时,可以完全不关注具体命令类,关注此类即可,调用getComn方法便可反射得到相应命令的实例。
但是很遗憾,这种方法也不是完全符合开闭原则的,原因在于,需要维护comnlist这个map。
所以,对于可扩展性的考虑如下:
需要增加命令时,完成以下2个步骤:
步骤1:继承相应的模式命令类,编写该命令类。
步骤2:在comnlist中增加相应的键值对。