友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第145部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
设计范式要表明的观点是“OOP 并不仅仅同多形性有关”。应当与 OOP 有关的是“将发生变化的东西同保持
不变的东西分隔开来”。多形性是达到这一目的的特别重要的手段。而且假如编程语言直接支持多形性,那
么它就显得尤其有用(由于直接支持,所以不必自己动手编写,从而节省大量的精力和时间)。但设计范式
向我们揭示的却是达到基本目标的另一些常规途径。而且一旦熟悉并掌握了它的用法,就会发现自己可以做
出更有创新性的设计。
由于《Design Patterns》这本书对程序员造成了如此重要的影响,所以他们纷纷开始寻找其他范式。随着的
时间的推移,这类范式必然会越来越多。JimCoplien (http://bell…labs。/~cope 主页作者)向我们
推荐了这样的一些站点,上面有许多很有价值的范式说明:
http://st…cs。uiuc。edu/users/patterns
http://c2。/cgi/wiki
http://c2。/ppr
http://bell…labs。/people/cope/Patterns/Process/index。html
http://bell…labs。/cgi…user/OrgPatterns/OrgPatterns
http://st…cs。uiuc。edu/cgi…bin/wikic/wikic
http://cs。wustl。edu/~schmidt/patterns。html
620
…………………………………………………………Page 622……………………………………………………………
http ://espinc。/patterns/overview。html
同时请留意每年都要召开一届权威性的设计范式会议,名为PLOP 。会议会出版许多学术论文,第三届已在
1997 年底召开过了,会议所有资料均由 Addison…Wesley 出版。
16。10 练习
(1) 将SingletonPattern。java 作为起点,创建一个类,用它管理自己固定数量的对象。
(2) 为TrashVisitor。java 添加一个名为Plastic (塑料)的类。
(3) 为DynaTrash。java 同样添加一个Plastic (塑料)类。
621
…………………………………………………………Page 623……………………………………………………………
第 17 章 项目
本章包含了一系列项目,它们都以本书介绍的内容为基础,并对早期的章节进行了一定程度的扩充。
与以前经历过的项目相比,这儿的大多数项目都明显要复杂得多,它们充分演示了新技术以及类库的运用。
17。1 文字处理
如果您有C 或C++的经验,那么最开始可能会对Java 控制文本的能力感到怀疑。事实上,我们最害怕的就是
速度特别慢,这可能妨碍我们创造能力的发挥。然而,Java 对应的工具(特别是String 类)具有很强的功
能,就象本节的例子展示的那样(而且性能也有一定程度的提升)。
正如大家即将看到的那样,建立这些例子的目的都是为了解决本书编制过程中遇到的一些问题。但是,它们
的能力并非仅止于此。通过简单的改造,即可让它们在其他场合大显身手。除此以外,它们还揭示出了本书
以前没有强调过的一项Java 特性。
17。1。1 提取代码列表
对于本书每一个完整的代码列表(不是代码段),大家无疑会注意到它们都用特殊的注释记号起始与结束
('//:'和'///:~')。之所以要包括这种标志信息,是为了能将代码从本书自动提取到兼容的源码文件中。
在我的前一本书里,我设计了一个系统,可将测试过的代码文件自动合并到书中。但对于这本书,我发现一
种更简便的做法是一旦通过了最初的测试,就把代码粘贴到书中。而且由于很难第一次就编译通过,所以我
在书的内部编辑代码。但如何提取并测试代码呢?这个程序就是关键。如果你打算解决一个文字处理的问
题,那么它也很有利用价值。该例也演示了String 类的许多特性。
我首先将整本书都以ASCII 文本格式保存成一个独立的文件。CodePackager 程序有两种运行模式(在
usageString 有相应的描述):如果使用…p 标志,程序就会检查一个包含了ASCII 文本(即本书的内容)的
一个输入文件。它会遍历这个文件,按照注释记号提取出代码,并用位于第一行的文件名来决定创建文件使
用什么名字。除此以外,在需要将文件置入一个特殊目录的时候,它还会检查package 语句(根据由
package 语句指定的路径选择)。
但这样还不够。程序还要对包(package)名进行跟踪,从而监视章内发生的变化。由于每一章使用的所有包
都以c02,c03,c04 等等起头,用于标记它们所属的是哪一章(除那些以 起头的以外,它们在对不同的
章进行跟踪的时候会被忽略)——只要每一章的第一个代码列表包含了一个package,所以CodePackager 程
序能知道每一章发生的变化,并将后续的文件放到新的子目录里。
每个文件提取出来时,都会置入一个SourceCodeFile 对象,随后再将那个对象置入一个集合(后面还会详尽
讲述这个过程)。这些 SourceCodeFile 对象可以简单地保存在文件中,那正是本项目的第二个用途。如果直
接调用 CodePackager,不添加…p 标志,它就会将一个“打包”文件作为输入。那个文件随后会被提取(释
放)进入单独的文件。所以…p 标志的意思就是提取出来的文件已被“打包”(packed)进入这个单一的文
件。
但为什么还要如此麻烦地使用打包文件呢?这是由于不同的计算机平台用不同的方式在文件里保存文本信
息。其中最大的问题是换行字符的表示方法;当然,还有可能存在另一些问题。然而,Java 有一种特殊类型
的IO 数据流——DataOutputStream——它可以保证“无论数据来自何种机器,只要使用一个
DataInputStream 收取这些数据,就可用本机正确的格式保存它们”。也就是说,Java 负责控制与不同平台
有关的所有细节,而这正是Java 最具魅力的一点。所以…p 标志能将所有东西都保存到单一的文件里,并采
用通用的格式。用户可从Web 下载这个文件以及 Java 程序,然后对这个文件运行CodePackager,同时不指
定…p 标志,文件便会释放到系统中正确的场所(亦可指定另一个子目录;否则就在当前目录创建子目录)。
为确保不会留下与特定平台有关的格式,凡是需要描述一个文件或路径的时候,我们就使用 File 对象。除此
以外,还有一项特别的安全措施:在每个子目录里都放入一个空文件;那个文件的名字指出在那个子目录里
应找到多少个文件。
下面是完整的代码,后面会对它进行详细的说明:
//: CodePackager。java
// 〃Packs〃 and 〃unpacks〃 the code in 〃Thinking
// in Java〃 for cross…platform distribution。
622
…………………………………………………………Page 624……………………………………………………………
/* mented so CodePackager sees it and starts
a new chapter directory; but so you don't
have to worry about the directory where this
program lives:
package c17;
*/
import java。util。*;
import java。io。*;
class Pr {
static void error(String e) {
System。err。println(〃ERROR: 〃 + e);
System。exit(1);
}
}
class IO {
static BufferedReader disOpen(File f) {
BufferedReader in = null;
try {
in = new BufferedReader(
new FileReader(f));
} catch(IOException e) {
Pr。error(〃could not open 〃 + f);
}
return in;
}
static BufferedReader disOpen(String fname) {
return disOpen(new File(fname));
}
static DataOutputStream dosOpen(File f) {
DataOutputStream in = null;
try {
in = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(f)));
} catch(IOException e) {
Pr。error(〃could not open 〃 + f);
}
return in;
}
static DataOutputStream dosOpen(String fname) {
return dosOpen(new File(fname));
}
static PrintWriter psOpen(File f) {
PrintWriter in = null;
try {
in = new PrintWriter(
new BufferedWriter(
new FileWriter(f)));
} catch(IOException e) {
Pr。error(〃could not open 〃 + f);
623
…………………………………………………………Page 625……………………………………………………………
}
return in;
}
static PrintWriter psOpen(String fname) {
return psOpen(new File(fname));
}
static void close(Writer os) {
try {
os。close();
} catch(IOException e) {
Pr。error(〃closing 〃 + os);
}
}
static void close(DataOutputStream os) {
try {
os。close();
} catch(IOException e) {
Pr。error(〃closing 〃 + os);
}
}
static void close(Reader os) {
try {
os。close();
} catch(IOException e) {
Pr。error(〃closing 〃 + os);
}
}
}
class SourceCodeFile {
public static final String
startMarker = 〃//:〃; // Start of source file
endMarker = 〃} ///:~〃; // End of source
endMarker2 = 〃}; ///:~〃; // C++ file end
beginContinue = 〃} ///:Continued〃;
endContinue = 〃///:Continuing〃;
packMarker = 〃###〃; // Packed file header tag
eol = // Line separator on current system
System。getProperty(〃line。separator〃);
filesep = // System's file path separator
System。getProperty(〃file。separator〃);
public static String copyright = 〃〃;
static {
try {
BufferedReader cr =
new BufferedReader(
new FileReader(〃Copyright。txt〃));
String crin;
while((crin = cr。readLine()) != null)
copyright += crin + 〃n〃;
cr。close();
} catch(Exception e) {
624
…………………………………………………………Page 626……………………………………………………………
copyright = 〃〃;
}
}
private String filename; dirname;
contents = new String();
private static String chapter = 〃c02〃;
// The file name separator from the old system:
public static String oldsep;
public String toString() {
return dirname + filesep + filename;
}
// Constructor for parsing from document file:
public SourceCodeFile(String firstLine;
BufferedReader in) {
dirname = chapter;
// Skip past marker:
filename = firstLine。substring(
startMarker。length())。trim();
// Find space that terminates file name:
if(filename。indexOf(' ') != …1)
filename = filename。substring(
0; filename。indexOf(' '));
System。out。println(〃found: 〃 + filename);
contents = firstLine + eol;
if(copyright。length() != 0)
contents += copyright + eol;
String s;
boolean foundEndMarker = false;
try {
while((s = in。readLine()) != null) {
if(s。startsWith(startMarker))
Pr。error(〃No end of file marker for 〃 +
filename);
// For this program; no spaces before
// the 〃package〃 keyword are allowed
// in the input source code:
else if(s。startsWith(〃package〃)) {
// Extract package name:
String pdir = s。substring(
s。indexOf(' '))。trim();
pdir = pdir。substring(
0; pdir。indexOf(';'))。trim();
// Capture the chapter from the package
// ignoring the '' subdirectories:
if(!pdir。startsWith(〃〃)) {
int firstDot = pdir。indexOf('。');
if(firstDot != …1)
chapter =
pdir。substring(0;firstDot);
else
chapter = pdir;
}
625
…………………………………………………………Page 627……………………………………………………………
// Convert package name to path name:
pdir = pdir。replace(
'。'; filesep。charAt(0));
System。out。println(〃package 〃 + pdir);
dirname = pdir;
}
contents += s + eol;
// Move past con
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!