一个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中增加相应的键值对。

 

源码:https://github.com/heynoodles/myvi

posted @ 2013-03-08 14:45  Alex_Monkey  阅读(1187)  评论(0编辑  收藏  举报