201631084230(只有我一个人,“合作者”这个标题有些不合适了)
https://gitee.com/mxhkkk/Wc/tree/complete/
https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2188
个人项目完成后,我看了很多人的作业博客,也评论了很多,但始终没有发出这样一条评论:“我们的程序设计风格很像,结对编程我们一起吧”,确实是没有发这样的评论。后来才发现,团队项目组队因此简单了,一个人再找一个两人组就可以了。
PSP2.1 | PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 30 | 20 |
Estimate | 估计这个任务需要多少时间 | 30 | 20 |
Development | 开发 | 290 | 640 |
Analysis | 需求分析 (包括学习新技术) | 30 | 20 |
Design Spec | 生成设计文档 | 0 | 0 |
Design Review | 设计复审 (和同事审核设计文档) | 0 | 0 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
Design | 具体设计 | 60 | 240 |
Coding | 具体编码 | 60 | 120 |
Code Review | 代码复审 | 30 | 90 |
Test | 测试(自我测试,修改代码,提交修改) | 90 | 30 |
Reporting | 报告 | 90 | 120 |
Test Report | 测试报告 | 0 | 0 |
Size Measurement | 计算工作量 | 0 | 0 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 470 | 730 |
发现现在的Command类完全变成了一个委托类,删除这一层次。
Parser返回handler的集合,Invoker直接调用handler执行方法。
删除GUI的调用策略,改为并行和串行两种调用策略。当处理文件有多个且计算机支持并行时采用并行策略,否则采用串行策略。
下面验证一下并行的效果如何:
并行的效果还是很明显的,我测试用的计算机是双核的,如果是四核、八核的计算机那就更快了,因为我在设计中考虑到了伸缩性。
测试文件的地址:https://gitee.com/mxhkkk/Wc/blob/complete/src/test/java/test.zip
有趣的是,测试文件夹大小有60多MB,而压缩后只有不到1MB,这是因为文件夹中有很多重复的文件,为了方便我直接复制进去的。这个现象引发了我对Wc程序的一个思考,我们也可以像压缩软件那样识别相同的文件,来避免重复计算。
并行任务类代码:
private static class Task implements Callable<ResultItems> {
private final List<AbstractHandler> handlers;
private final File file;
public Task(List<AbstractHandler> handlers, File file) {
this.handlers = handlers;
this.file = file;
}
@Override
public ResultItems call() throws Exception {
ResultItems items = new ResultItems();
for (AbstractHandler handler : handlers) {
items.add(handler.execute(file));
}
return items;
}
}
为WcFrame添加操作类,分离类的职责
为WcFrame添加一个取消按钮,并将计算操作移到其他线程中,提高GUI的页面响应性
WcFrameOper中计算并设置结果的代码:
public void calculateAndSetResult() {
SwingUtilities.invokeLater(() -> frame.setBusyState());
future = exec.submit(new CalculateTask());
String result = null;
try {
result = future.get();
} catch (InterruptedException e) {
result = "任务失败";
} catch (ExecutionException e) {
result = "任务失败";
} catch (CancellationException e) {
result = "任务取消";
}
final String finalResult = result;
SwingUtilities.invokeLater(() -> {
frame.setResult(finalResult);
frame.setLeisureState();
});
}
有些函数式编程思想会使代码更简单,比如集合排序及toString():
@Override
public String toString() {
return items.stream()
.sorted(Comparator.comparingLong(ResultItem::separatorCount).thenComparing(ResultItem::getFileName)
.thenComparingInt(ResultItem::getId))
.parallel().map(ResultItem::toString).collect(Collectors.joining("\r\n"));
}
在单个文件的处理过程中也可以基于流的思想来实现并行,这要求统一handler类的处理过程,并将字符流在多个handler之间传递,但受现在程序结构的限制,实现这一想法是非常困难的。好在有高层次多个文件处理的并行,程序对CPU的利用率还算可以,但在处理单个超大文件时就不适用了。
CliParser类的部分测试代码
@Before
public void setup() {
FileName.restore();
}
@Test()
public void testGuiFailHasOtherOption() {
String[] args = new String[] { "-x", "-w" };
try {
new CliParser().parse(args);
fail();
} catch (ParseException e) {
assertEquals(ParseExceptionMess.CLI_SYSTEM_MESS, e.getMessage());
}
}
@Test()
public void testGuiFailHasArg() {
String[] args = new String[] { "-x", "code.txt" };
try {
new CliParser().parse(args);
fail();
} catch (ParseException e) {
assertEquals(ParseExceptionMess.GUI_USE_ALONE, e.getMessage());
}
}
handler包的部分测试代码
@Test
public void testExecute() throws IOException {
File stopFile = new File("D:\\eclipse_n_java\\Wc\\src\\test\\java\\com\\mxh\\wc\\handler\\stopWord.txt");
Files.getInstance().setStopWordFile(stopFile);
File file = new File("D:\\eclipse_n_java\\Wc\\src\\test\\java\\com\\mxh\\wc\\handler\\testStopWords.txt");
SelectWordCountHandler handler = new SelectWordCountHandler();
assertEquals(new ResultItem(file.getPath(), Args.STOP, 20), handler.execute(file));
}
个人编程过程中,会有很多意外的错误,这些错误大多是由于某个细节的疏忽而造成的,结对编程就可以很好地避免这一问题,两人都犯同一个低级错误的概率很小。不得不说,我浪费了一次结对编程的机会。
原文:https://www.cnblogs.com/mxhkkk/p/9806375.html