zoukankan      html  css  js  c++  java
  • 一个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

  • 相关阅读:
    Android TTS
    观察者模式(C++实现)
    android 8未知来源app安装
    NotificationChannel
    java底层知识
    Java14
    数据库分区、分库分表
    二叉搜索树的第k大节点
    从上到下按层打印二叉树
    springcloud面试知识点
  • 原文地址:https://www.cnblogs.com/forstudy/p/2815352.html
Copyright © 2011-2022 走看看