< Day Day Up > |
The framework of Unix pipes and filters is elegant. It is easier to create a program that does one simple job (a filter) than a program that does multiple jobs. For example, the word count program ( wc ) counts lines, words, and characters in the input file. The directory-listing program ( ls ) lists the files in a directory, one per line. To count how many files are in a directory, you pipe the output of the ls program into the input of the wc program and count the number of lines (e.g., ls wc ). [*]
Each class should capture one concept. Likewise, each method within a class should do one little job well. The Proxy pattern works in this way. Each proxy class can perform one operation (e.g., encryption or checking for security access violations). Once a proxy method has finished its task, it calls the corresponding method in another proxy object to perform further operations. Multilevel delegation works in a similar manner. The lowest -level class performs simple operations. Higher-level classes perform more complicated operations, which are based on the lower-level operations. The lowest-level classes get used more often, and the higher-level classes are used less often, since they are designed for specific purposes. For example, here is a File class that just reads a set of characters from a file: class File boolean open (String filename) void close( ) char read_a_char( ) void write_a_char(char char_to_write) The read_a_char( ) method internally might not read just a character from the operating system. The method might read an entire buffer and then return the characters one at a time. Performance is a quality-of-implementation issue, not an interface issue. However, if we found that we were calling read_a_char( ) in a loop in many places, we might add a more efficient interface method, such as read_array_of_char(char [] array) . This is an interface performance issue, not an internal implementation concern. On the next level up, we might want to read characters until a newline is read. Instead of modifying File , we create a new class to read lines, and delegate the actual file reading to File . For example, we might have the following: class FileWithLines String read_line_up_to_new_line_and_toss_new_line( ) Alternatively, we could have added this method to the File class. If we took that approach for other operations, we would be burdening the File class with a number of unrelated methods . The File class should do its one job well. FileWithLines can incorporate other methods dealing with line-oriented input. For example, we could add get_count_of_lines_read( ) , set_line_terminator( ) , and so forth. In another project, we might read a file that contains keywords and associated values. The class might be as follows : class KeywordPair String keyword String value class FileWithKeywords KeywordPair read_next_keyword_pair( ) Once again, the file reading is delegated to the File class. If the keyword pairs were kept on separate lines, the reading might be delegated to the FileWithLines class.
|
< Day Day Up > |