首页 > 其他 > 详细

系统分析与设计课程项目 WordCount 结对编程

时间:2018-10-17 19:20:23      阅读:155      评论:0      收藏:0      [点我收藏+]

系统分析与设计课程项目 WordCount 结对编程

作业说明

合作者:

201631084230(只有我一个人,“合作者”这个标题有些不合适了)

代码地址:

https://gitee.com/mxhkkk/Wc/tree/complete/

本次作业的链接地址:

https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2188

为什么只有我一个人

个人项目完成后,我看了很多人的作业博客,也评论了很多,但始终没有发出这样一条评论:“我们的程序设计风格很像,结对编程我们一起吧”,确实是没有发这样的评论。后来才发现,团队项目组队因此简单了,一个人再找一个两人组就可以了。

PSP表格

PSP2.1PSP阶段预估耗时(分钟)实际耗时(分钟)
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
合计470730

自审

  • 命令行参数解析,不准确,没有错误提示信息。我现在意识到这是一个复杂的过程,决定使用CLI来重构。
  • 根据文件名来生成文件的操作类,这也挺复杂的。有三种不同形式的文件,文件名必须是合法的,文件名中可能带有路径,还有文件通配符的处理,是否支持文件夹操作以及文件夹的递归。
  • 统计过程是低效的,在设计和性能之间无法做到很好地权衡。
  • 结果类似乎没有必要应用组合模式。
  • 不能很好地利用流的思想来做设计。

修复问题及关键代码

删除Command层

发现现在的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;
    }
}

将GUI类界面显示与操作职责分离

为WcFrame添加操作类,分离类的职责

技术分享图片

为GUI添加取消操作,并提高GUI界面的响应性

为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的利用率还算可以,但在处理单个超大文件时就不适用了。

部分测试代码(使用JUnit4)

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));
}

总结

个人编程过程中,会有很多意外的错误,这些错误大多是由于某个细节的疏忽而造成的,结对编程就可以很好地避免这一问题,两人都犯同一个低级错误的概率很小。不得不说,我浪费了一次结对编程的机会。

系统分析与设计课程项目 WordCount 结对编程

原文:https://www.cnblogs.com/mxhkkk/p/9806375.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!