C++算法学习——经典的抽象设计——buffer(1)

来源:互联网 发布:用户管理系统java 编辑:程序博客网 时间:2024/06/15 01:29

编辑缓冲区的概念

无论何时发送短信或编辑其中一个程序的源文件,你都会使用一个编辑器,它是一个软件应用程序,允许你创建和更改由字符组成的文件。在内部,编辑器保存维持一系列字符,这个区域通常称为缓冲区(buffer)。编辑器应用程序允许你对缓冲区的内容执行各种操作,其中许多操作仅限于缓冲区中当前的位置,缓冲区中的当前位置通过称为光标(cursor)的符号在屏幕上标记,该符号通常显示为两个字符,编辑者在支持哪些操作上有所不同,但所有编辑都支持以下操作:

  • 将光标移动到要进行编辑的文本中的点。
  • 输入新文本,然后将其插入当前的光标位置。
  • 使用DELETE或BACKSPACE键删除字符

现代编辑通常提供高度复杂的编辑环境,具有使用鼠标定位光标或搜索特定文本字符串的命令等特色。 此外,它们倾向于在执行时精确地显示所有编辑操作的结果。在整个编辑过程中显示缓冲区的当前内容的编辑器称为wysiwyg(发音为“wizzy-wig”)编辑器,这是“what you see is what you get(你看到的是你所得到的)”的缩写。这样的编辑器很容易使用,但是所有这些高级功能使你更难看出编辑器在内部的工作原理。
在计算的早期,编辑器要简单得多。编辑器无法访问鼠标或复杂的图形显示器,所以它只能响应键盘上输入的命令。例如,使用典型的基于键盘的编辑器,通过键入命令字母I,然后是一系列字符来插入新文本。附加命令执行其他编辑功能,例如在缓冲区中移动光标。通过输入这些命令的正确组合,可以进行任何所需的更改。就如同下表格:

命令 作用 F 将编辑光标向前移动一个字符位置。 B 将编辑光标向后移动一个字符位置。 J 跳到缓冲区的开头。 E 将光标移动到缓冲区的末尾。 Ixxx 在当前光标位置插入xxx。 D 删除当前光标位置后的字符。 Q 退出编辑器程序。

除了I命令(也是插入字符)之外,每个编辑器命令都包含一行在一行中读取的单个字母。我们接下来的任务就是实现这个编辑器。
以下示例运行将说明编辑器的操作以及描述每个操作的注释。 在该会话中,用户首先插入字符axc,然后将缓冲区的内容更正为abc
这里写图片描述
编辑器程序显示每个命令后缓冲区的状态。 正如你在样品运行中可以看到的那样,程序用下一行用克拉符号(^)标记光标的位置。 这种行为不是你在真正的编辑器中所期望的,而是可以很容易地看到正在发生的事情。一旦你调试了编辑器缓冲区抽象,你可以更改主程序以将其嵌入到现代wysiwyg编辑器中。

定义一个缓存区的抽象

你的主要任务是设计维护编辑器缓冲区状态的数据结构。该数据结构必须跟踪缓冲区中的哪些字符以及光标所在的位置。每当执行编辑操作时,它也必须能够更新缓冲区内容。换句话说,你想做的是定义一个代表编辑器缓冲区的新抽象。
即使在这个早期阶段,你可能会对内部数据结构可能适当的一些想法。因为缓冲区显然是一个有序的字符序列,一个看似明显的选择是使用一个string或者一个Vector 作为底层表示。只要你有这些类可用,这将是一个适当的选择。 但是,我们的目标是了解表示形式的选择如何影响应用程序的效率。如果你使用像“string”和“vector”这样的更高级别的结构,那么很难做到这一点,因为这些类的内部工作对客户端是不可见的。如果你选择将其实现限制为内置数据结构,则每个操作都将变得可见,因此,确定各种竞争设计的相对效率将变得更加容易。该逻辑表明我们将使用字符数组作为底层表示,因为数组操作没有隐藏。
尽管使用一个数组表示缓冲区当然是一个解决这个问题的合理的方法,但还有其他的表示方式可以提供有趣的可能性。但是我们的基本理念(实际上大部分内容),是你不应该如此快地选择一个特定的代表。。 在编辑器缓冲区的情况下,数组只是几个选项之一,每个选项都有一些优点和缺点。在评估权衡后,你可能会决定在某种情况下使用一种策略,另一种策略则采用不同的策略。同时,重要的是要注意,无论选择什么样的代码,编辑器必须始终能够执行相同的命令集。因此,即使底层表示更改,编辑器缓冲区的外部行为必须保持不变。
为了使接口尽可能灵活,定义一个新类来表示编辑器缓冲区是有意义的。在这种情况下使用类的主要优点是,这样做可以让你分离行为和表示的规范。由于你了解必须响应的操作,所以表示你已经知道编辑器缓冲区的行为。在 buffer.h 接口中,你定义EditorBuffer类,其public接口提供所需的一组操作,而数据表示保持私有。客户端通过他们的公共接口完全使用EditorBuffer对象,无需访问底层的私有数据。反过来,这样做可以让你随意更改表示形式,而无需你的客户对其程序进行任何更改。

EditorBuffer类的public接口

公共接口包括用于在编辑器缓冲区上实现原始操作的方法的原型。你需要定义哪些操作?如果没有别的,你需要六个编辑器命令中的每一个的方法。然而,与任何类一样,你还需要定义一个初始化新缓冲区的构造函数。给定EditorBuffer的类名,构造函数的原型将是:

EditorBuffer()

对应的析构函数是:

~EditorBuffer()

用于释放它的内存空间。
下一步是定义编辑命令的原型。 例如,要向前移动光标,可以定义一个方法:

void moveCursorForward();

在设计接口时,请务必记住,你不必担心如何执行这样的操作,或者说缓冲区和光标如何被表示。 moveCursorForward方法完全根据其抽象效果来定义。
创建简单编辑器应用程序所需的最后一个方法是显示缓冲区的内容,包括光标的位置。为了实例的目的,将该操作作为方法导出是有意义的,因为每个不同的表示需要略微不同的代码来显示缓冲器内容。因此,buffer.h接口中的最后一个条目:

void showContents();

所以我们的EditorBuffer类的pubic接口如下:

#ifndef _buffer_h#define _buffer_h/* *下面的部分为buffer.h类的公开部分,其私有部分我们隐藏在bufferpriv.h文件中 *用#include命令导入,这里面包括了 构造函数,析构函数,以及各种行为 */ class EditorBuffer{    public:    /*     *构造函数: EditorBuffer     *用法:EditorBuffer buffer     *-------------------------     *作用:建立一个空的编辑器缓存     */    EditorBuffer();    /*     *析构函数:~EditorBuffer     *用法:常常隐式调用      *-------------------------     *作用:释放这个buffer在堆中占用的空间      */     ~EditorBuffer();     /*      *方法:moveCursorForward()             moveCursorBackward()      *用法:buffer.moveCursorForward();             buffer.moveCursorBackward();      *---------------------------      *这个方法把游标往前或者往后移动一个字符      *特别地,当游标位于buffer的第一号位置或者末尾时,这个方法      *不再起作用      */     void moveCursorForward();     void moveCursorBackward();     /*      *方法: moveCursorToStart();              moveCursorToEnd();      *用法:buffer. moveCursorToStart()             buffer.moveCursorToEnd()      *-------------------------------      *这个方法把游标移动到缓存的开头或者末尾      */     void moveCursorToStart();     void moveCursorToEnd();     /*      *方法:insertCharacter(char ch);      *用法:buffer.insertCharacter(char ch);      *-------------------------------------      *在buffer的游标处插入单个字符,随后游标紧跟在被插入的字符      *的后面      */       void insertCharacter(char ch);     /*      *方法:delecteCharacter      *用法:buffer.delecteCharacter()      *-------------------------------      *立即删除游标后面的单个字符,如果游标在buffer的末尾,那么      *方法将不起作用      */      void delecteCharacter();     /*      *方法:showContents      *用法:buffer.showContents      *----------------------------      *将buffer中的内容在控制台中显示出来,然后标记      *光标的位置      */      void showContents();      #include "bufferpriv.h"  };  #endif
阅读全文
0 0
原创粉丝点击