WordCount
码云上的项目地址:https://gitee.com/heypin/WordCount
本次作业的链接地址:https://edu.cnblogs.com/campus/xnsy/Test/homework/2203
设计思路
首先配置下面图片中的options.xml文件,然后读取文件信息将这些支持的命令行封装到Apache CLI库的Options类中,再通过CLI库解析命令行解析出输入了哪些Option以及他们的值,如果配置文件写的有多个参数,将获取到多个参数。
然后对每个命令行参数都建立一个类,每个类实现一个命令行参数的功能,如LineCount类实现-l命令,WordCount实现-w命令,OutputGraph实现-x命令,除了递归命令-s的实现类Recursion,其他命令对应的类都实现了IStatis接口。
最后通过java的反射机制,这里是用的spring的库来反射,将解析到的命令对应的类循环实例化,调用这些类的共同接口IStatis的statis方法执行相应的功能,statis方法的参数由main函数和StatisUtil工具类负责将解析到的参数传给它们。
解析命令行主要代码
public class StatisUtil { public static Element getOptionConfigRoot() throws DocumentException { SAXReader reader = new SAXReader(); Document document = reader.read(new StatisUtil() .getClass().getClassLoader().getResource("options.xml")); return document.getRootElement(); } public static Options getAllOptions() throws DocumentException { Options options=new Options(); Iterator<Element> it = getOptionConfigRoot().elementIterator(); while( it.hasNext()) { Element element = it.next(); Option option=Option.builder(element.attributeValue("opt")) .hasArg(Boolean.parseBoolean(element.attributeValue("hasArg"))) .argName(element.attributeValue("argName")) .numberOfArgs(Integer.parseInt(element.attributeValue("numberOfArgs"))) .optionalArg(Boolean.parseBoolean(element.attributeValue("optionalArg"))) .build(); options.addOption(option); } return options; } public static String getCommonParam(Option[] cmdOptions) { String commonParam=null; for(int i=0;i<cmdOptions.length;++i) { if(cmdOptions[i].hasArg()&&cmdOptions[i].hasOptionalArg() &&cmdOptions[i].getValue()!=null){ commonParam=cmdOptions[i].getValue(); } } return commonParam; } public static Option[] optionsToArray(Options options) { Collection<Option> opts=options.getOptions(); Option[] optArray=new Option[opts.size()]; opts.toArray(optArray); return optArray; } public static Options getMatchOptions(Options options,String matchArgName) { Options matchOptions=new Options(); Collection<Option> opts=options.getOptions(); for(Option option:opts){ if(option.getArgName().contains(matchArgName)){ matchOptions.addOption(option); } } return matchOptions; } public static void executeCommandLine(Option[] cmdOptions,StringWriter writer) { @SuppressWarnings("resource") ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml"); String commonParam=getCommonParam(cmdOptions); for(int i=0;i<cmdOptions.length;++i) { IStatis statis=(IStatis) context.getBean(cmdOptions[i].getOpt()); if(cmdOptions[i].hasArgs()) { statis.statis(writer,cmdOptions[i].getValues()); } else { if(cmdOptions[i].hasOptionalArg()&&cmdOptions[i].getValue()==null) statis.statis(writer,commonParam); else statis.statis(writer,cmdOptions[i].getValue()); } } } public static String executeOptions(Option[] options,String fileName) throws IOException { @SuppressWarnings("resource") ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml"); StringWriter writer=new StringWriter(); for(int i=0;i<options.length;++i) { IStatis statis=(IStatis) context.getBean(options[i].getOpt()); statis.statis(writer,fileName); } writer.close(); return writer.getBuffer().toString(); } }
public class MainClass { public static CommandLine cmd=null; public static void main(String[] args) { CommandLineParser parser=new DefaultParser(); cmd= parser.parse(StatisUtil.getAllOptions(), args); if(!cmd.hasOption("s")) { StringWriter writer=new StringWriter(); StatisUtil.executeCommandLine(cmd.getOptions(),writer); if(!cmd.hasOption("o"))//有输出到文件命令时不打印 System.out.println(writer.getBuffer().toString()); writer.close(); } else { List<File> matchFile=new Recursion().recursion(StatisUtil.getCommonParam(cmd.getOptions())); CommandLine newCmd=parser.parse(StatisUtil.getMatchOptions(StatisUtil.getAllOptions(),"recursion"), args); if(matchFile.size()==0) System.out.println("无匹配的文件"); for(File file:matchFile) System.out.println(StatisUtil.executeOptions(newCmd.getOptions(), file.getAbsolutePath())); } }
运行结果
静态代码检查情况
使用PMD工具进行静态代码检查,经检查代码检查无较大问题,主要提示规则CommentRequired,因代码暂未写注释,而有些地方最好添加注释。
单元测试情况
采用JUnit5进行单元测试,主要对统计行数、字符数、代码行数等进行单元测试,单元测试的代码如下:
package com.statis.impl.test; import static org.junit.jupiter.api.Assertions.*; import java.io.StringWriter; import org.junit.jupiter.api.Test; import com.statis.impl.CharCount; import com.statis.impl.CodeCount; import com.statis.impl.LineCount; import com.statis.impl.WordCount; class CountTest { public String fileName="C:\\Users\\22443\\Desktop\\test.txt"; @Test void charCountTest() { StringWriter writer=new StringWriter(); new CharCount().statis(writer, fileName); String result=fileName+",字符数为:133\n"; assertTrue(result.equals(writer.getBuffer().toString())); } @Test void LineCountTest() { StringWriter writer=new StringWriter(); new LineCount().statis(writer, fileName); String result=fileName+",行数为:11\n"; assertTrue(result.equals(writer.getBuffer().toString())); } @Test void WordCount() { StringWriter writer=new StringWriter(); new WordCount().statis(writer, fileName); String result=fileName+",词数为:18\n"; assertTrue(result.equals(writer.getBuffer().toString())); } @Test void codeCountTest() { StringWriter writer=new StringWriter(); new CodeCount().statis(writer, fileName); String result=fileName+",空行数为:3\n" +fileName+",注释行数为:5\n" +fileName+",代码行数为:3\n"; assertTrue(result.equals(writer.getBuffer().toString())); } }
测试文本:
单元测试结果: 单元测试全部通过