更好的方法是使文本类更通用。仅应根据基本文本功能定义其 API,而不应反映将用其实现的更高级别的操作。例如,只需两种方法即可修改文本:
void insert(Position position, String newText);
void delete(Position start, Position end);
第一种方法在文本内的任意位置插入任意字符串,第二种方法删除大于或等于开始但小于结束的位置处的所有字符。此 API 还使用了更通用的 Position 类型来代替 Cursor,它反映了特定的用户界面。文本类还应该提供用于操纵文本中位置的通用工具,例如:
Position changePosition(Position position, int numChars);
此方法返回一个新位置,该位置与给定位置相距给定字符数。如果 numChars 参数为正,则新位置在文件中比位置晚;如果 numChars 为负,则新位置在位置之前。必要时,该方法会自动跳到下一行或上一行。使用这些方法,可以使用以下代码来实现删除键(假定 cursor 变量保留当前光标的位置):
text.delete(cursor, text.changePosition(cursor, 1));
同样,可以按以下方式实现退格键:
text.delete(text.changePosition(cursor, -1), cursor);
使用通用文本 API,实现用户界面功能(如删除和退格)的代码比使用专用文本 API 的原始方法要长一些。但是,新代码比旧代码更明显。在用户界面模块中工作的开发人员可能会关心由 Backspace 键删除哪些字符。使用新代码,这是显而易见的。使用旧代码,开发人员必须转到文本类并阅读退格方法的文档和/或代码以验证行为。此外,通用方法总体上比专用方法具有更少的代码,因为它用较少数量的通用方法代替了文本类中的大量专用方法。
使用通用接口实现的文本类除交互式编辑器外,还可以用于其他目的。作为一个示例,假设您正在构建一个应用程序,该应用程序通过将所有出现的特定字符串替换为另一个字符串来修改指定文件。专用文本类中的方法(例如,退格键和 Delete)对于此应用程序几乎没有价值。但是,通用文本类已经具有新应用程序所需的大多数功能。缺少的只是一种搜索给定字符串的下一个匹配项的方法,例如:
Position findNext(Position start, String string);
当然,交互式文本编辑器可能具有搜索和替换的机制,在这种情况下,文本类将已经包含此方法。
A better approach is to make the text class more generic. Its API should be defined only in terms of basic text features, without reflecting the higher-level operations that will be implemented with it. For example, only two methods are needed for modifying text:
void insert(Position position, String newText);
void delete(Position start, Position end);
The first method inserts an arbitrary string at an arbitrary position within the text, and the second method deletes all of the characters at positions greater than or equal to start but less than end. This API also uses a more generic type Position instead of Cursor, which reflects a specific user interface. The text class should also provide general-purpose facilities for manipulating positions within the text, such as the following:
Position changePosition(Position position, int numChars);
This method returns a new position that is a given number of characters away from a given position. If the numChars argument is positive, the new position is later in the file than position; if numChars is negative, the new position is before position. The method automatically skips to the next or previous line when necessary. With these methods, the delete key can be implemented with the following code (assuming the cursor variable holds the current cursor position):
text.delete(cursor, text.changePosition(cursor, 1));
Similarly, the backspace key can be implemented as follows:
text.delete(text.changePosition(cursor, -1), cursor);
With the general-purpose text API, the code to implement user interface functions such as delete and backspace is a bit longer than with the original approach using a specialized text API. However, the new code is more obvious than the old code. A developer working in the user interface module probably cares about which characters are deleted by the backspace key. With the new code, this is obvious. With the old code, the developer had to go to the text class and read the documentation and/or code of the backspace method to verify the behavior. Furthermore, the general-purpose approach has less code overall than the specialized approach, since it replaces a large number of special-purpose methods in the text class with a smaller number of general-purpose ones.
A text class implemented with the general-purpose interface could potentially be used for other purposes besides an interactive editor. As one example, suppose you were building an application that modified a specified file by replacing all occurrences of a particular string with another string. Methods from the specialized text class, such as backspace and delete, would have little value for this application. However, the general-purpose text class would already have most of the functionality needed for the new application. All that is missing is a method to search for the next occurrence of a given string, such as this:
Position findNext(Position start, String string);
Of course, an interactive text editor is likely to have a mechanism for searching and replacing, in which case the text class would already include this method.