结对编程-WordCount(Java)
说明
合作者
201631062221,201631062514
项目码云链接
作业链接
https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2188
https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2120
正文
结对编程PSP表格
PSP2.1 | PSP阶段 | 预估耗时 | 实际耗时 |
(分钟) | (分钟) | ||
Planning | 计划 | 60 | 40 |
· Estimate | · 估计这个任务需要多少时间 | 60 | 40 |
Development | 开发 | 480 | 720 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 250 |
· Design Spec | · 生成设计文档 | 30 | 60 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
· Design | · 具体设计 | 30 | 10 |
· Coding | · 具体编码 | 360 | 600 |
· Code Review | · 代码复审 | 30 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 240 |
Reporting | 报告 | 30 | 60 |
· Test Report | · 测试报告 | 30 | 10 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 60 | 60 |
合计 | 1410 | 2170 | |
代码复审情况
代码复审中发现一些问题,他的代码在实现基础功能的时候没有考虑到新需求的加入,将所有的逻辑都放在了主类中来处理,造成各种flag一起存在,逻辑比较混乱,如果要添加新的需求,则需要对整个逻辑过程进行修改,要看懂他写的代码已经是很难受的了,如果还要对之进行修改,那是一个更加痛苦的过程。不仅 如此,在最初的结构中,他的一个类会去负责好几个功能,不符合单一职责原则。不过在后来的扩展的时候,我们对之前的代码进行了较大的改造,从结构上来看,有了一定的条理性!
设计过程
这次项目结对部分比较少,结对的大部分时间都花在了基础功能的代码复审上,拓展功能和高级功能才是比较花时间的地方,我和小组另一名成员分工合作,我负责高级功能界面的编写和给他后台的参数传递,设计过程我主要关注自己的界面设计,少部分关注点在与另一名小组成员的后台处理数据的交互。
对于高级功能的设计主要采用Java Swing设计,设计一个主面板,上面放置各个控件,几个checkbox用于用户多选勾选命令,几个button,对应的点击事件使用filechooser控件寻找文件或文件夹,有一个textfile文本框用于用户输入批量处理的文件类型,最后一个提交按钮,传递一个命令集合到后台小组成员的类中,实现界面和后台的交互。
代码
TableTest类
这个类是界面类,主要生成各种控件和控件点击事件以及文件过滤器的编写
import java.awt.Checkbox;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseWheelEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import javax.print.attribute.standard.RequestingUserName;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;
import org.omg.CORBA.PUBLIC_MEMBER;
public class TableTest {
public static void main(String[] args) {
/*主界面*/
JFrame frame=new JFrame("WordCount");//软件左上角名称,新建一个界面
frame.setSize(400, 300);//500为长,300为宽
frame.setLocation(400, 300);//为出现在屏幕上位置
frame.setLayout(null);
/*面板一*/
JPanel j1=new JPanel();//新建一个面板
j1.setBounds(50, 50, 300, 60);//一二参数:位置,三四参数:填充大小
j1.setBackground(Color.white); // 设置面板背景颜色
// j1.setLayout(null);// 这一句可以没有,因为JPanel默认就是采用的FlowLayout
j1.setLayout(new FlowLayout());
/*组件:复选框*/
JLabel jfunctionView=new JLabel(" 程序功能");
JCheckBox jcb1=new JCheckBox("行数统计");
JCheckBox jcb2=new JCheckBox("字符统计");
JCheckBox jcb3=new JCheckBox("单词统计");
JCheckBox jcb4=new JCheckBox("代码行/注释行/空行");
JCheckBox jcb5=new JCheckBox("批量操作");
jcb1.setSelected(false);
jcb2.setSelected(false);
jcb3.setSelected(false);
jcb4.setSelected(false);
jcb5.setSelected(false);
j1.add(jfunctionView);
j1.add(jcb1);
j1.add(jcb2);
j1.add(jcb3);
j1.add(jcb4);
j1.add(jcb5);
/**
* 面板二***********************************************
*
* */
JPanel j2=new JPanel();
j2.setBounds(10, 150, 300, 60);
j2.setBackground(Color.lightGray);
/*组件:文件选择器*/
final JFileChooser fc=new JFileChooser();//文件选择器,用于基础功能实现
final JFileChooser pc=new JFileChooser();//目录选择器,用于批量操作实现
final JFileChooser sc=new JFileChooser();//文件选择器,用于保存文件实现
pc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);//设置只能选择目录
/*文件类型过滤器*/
fc.setFileFilter(new FileFilter() {
/*要求只接受.java文件*/
@Override
public String getDescription() {
return ".java";
}
@Override
public boolean accept(File f) {
return f.getName().toLowerCase().endsWith(".java");
}
});
JButton bOpen=new JButton("选择源码文件");
JButton bSave=new JButton("选择输出文件");
JButton bStop=new JButton("选择停止词文件");
JTextField jFileType=new JTextField("");
jFileType.addFocusListener(new JTextFieldHintListener(jFileType,"请输入文件类型,如\"*.java\""));
jFileType.setPreferredSize(new Dimension(150, 30));
JButton bPath=new JButton("选择文件目录");
JButton jsbumit=new JButton("提交");
jsbumit.setPreferredSize(new Dimension(120, 30));
// 把按钮加入面板
j2.add(bOpen);
j2.add(bSave);
j2.add(bStop);
j2.add(jFileType);
j2.add(bPath);
j2.add(jsbumit);
CommandSet tempcs=new CommandSet();
/*为打开文件按钮添加点击事件*/
bOpen.addActionListener(new ActionListener() {
public String filePath;
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
int retVal=fc.showOpenDialog(frame);
File file=fc.getSelectedFile();
if(retVal==JFileChooser.APPROVE_OPTION){
JOptionPane.showMessageDialog(frame, "你选择了文件:"+file.getAbsolutePath());
filePath=file.getAbsolutePath();
tempcs.setSourceFile(filePath);
}
}
});
/*为打开文件目录按钮添加点击事件*/
bPath.addActionListener(new ActionListener() {
public String filePath;
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
int retVal=pc.showOpenDialog(frame);
File file=pc.getSelectedFile();
if(retVal==JFileChooser.APPROVE_OPTION)
{
JOptionPane.showMessageDialog(frame, "你选择了文件夹:"+file.getAbsolutePath());
filePath=file.getAbsolutePath();
tempcs.setFilePath(filePath);
}
}
});
bSave.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
int option=sc.showSaveDialog(null);
if(option==JFileChooser.APPROVE_OPTION)
{
File file=sc.getSelectedFile();
FileOutputStream fos;
JOptionPane.showMessageDialog(frame, "保存文件路径为:"+file.getAbsolutePath());
tempcs.setOutFile(file.getAbsolutePath());
tempcs.setComO("-o");
try {
fos = new FileOutputStream(file);
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
/*为选择停止词文件添加点击事件*/
bStop.addActionListener(new ActionListener() {
public String filePath;
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
int retVal=fc.showOpenDialog(frame);
File file=fc.getSelectedFile();
if(retVal==JFileChooser.APPROVE_OPTION)
{
tempcs.setComE("-e");
JOptionPane.showMessageDialog(frame, "停止文件为:"+file.getAbsolutePath());
filePath=file.getAbsolutePath();
tempcs.setStopFile(filePath);
}
}
});
/*为提交按钮添加点击事件*/
jsbumit.addActionListener(new ActionListener() {
CommandSet cSet=new CommandSet();
@Override
public void actionPerformed(ActionEvent e) {
/*判断checkbox是否选中*/
if(jcb1.isSelected()){
cSet.setComLine("-l");
}
if(jcb2.isSelected()){
cSet.setComChar("-c");
}
if(jcb3.isSelected()){
cSet.setComWord("-w");
}
if(jcb4.isSelected()){
cSet.setComAdva("-a");
}
if(jcb5.isSelected()){
cSet.setComBatch("-s");
//bPath.setEnabled(true);
}
/*获得输入框文件类型*/
String fileType=jFileType.getText();
if(fileType.startsWith("*")){
cSet.setFileType(fileType);
}
else{
JOptionPane.showMessageDialog(frame, "对不起,你输入的不是一个合法的文件类型,请以\"*\"开始");
}
cSet.setSourceFile(tempcs.getSourceFile());
cSet.setOutFile(tempcs.getOutFile());
cSet.setFilePath(tempcs.getFilePath());
cSet.setStopFile(tempcs.getStopFile());
cSet.setComE(tempcs.getComE());
cSet.setComO(tempcs.getComO());
for(String s:cSet.getCommand())
{
System.out.println(s);
}
JOptionPane.showMessageDialog(frame, "恭喜你,操作成功");
//这里还有小组成员的调用代码,未整合到我的代码上,将在小组成员的链接中给出
}
});
/*设置双界面格式*/
JSplitPane sp=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,j1,j2);
sp.setDividerLocation(150);
frame.setContentPane(sp);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);//设置可见度显示
}
}
JTextFiledHintListener类
该类为输入焦点框提供逻辑,实现默认提示信息的显示和用户点击输入框时自动清除默认内容
/*为输入框焦点事件添加逻辑*/
class JTextFieldHintListener implements FocusListener {
private String hintText;
private JTextField textField;
public JTextFieldHintListener(JTextField jTextField,String hintText) {
this.textField = jTextField;
this.hintText = hintText;
jTextField.setText(hintText); //默认直接显示
jTextField.setForeground(Color.GRAY);
}
@Override
public void focusGained(FocusEvent e) {
//获取焦点时,清空提示内容
String temp = textField.getText();
if(temp.equals(hintText)) {
textField.setText("");
textField.setForeground(Color.BLACK);
}
}
@Override
public void focusLost(FocusEvent e) {
//失去焦点时,没有输入内容,显示提示内容
String temp = textField.getText();
if(temp.equals("")) {
textField.setForeground(Color.GRAY);
textField.setText(hintText);
}
}
}
CommandSet类
该类集合了小组成员后台需要的命令,通过面向对象的思想抽象出来,在节目中读取到用户命令成功后传递给后台小组成员类中
import java.util.ArrayList;
import java.util.List;
public class CommandSet {
private String comLine;//行数命令 -l
private String comChar;//字符数命令 -c
private String comWord;//单词数命令 -w
private String comAdva;//扩展功能,空行/注释行/代码行 -a
private String comBatch;//批量操作命令 -s
private String comO;//输出文件命令-o
private String comE;//停用词命令-e
private String sourceFile;//源文件目录
private String filePath;//选择批量操作文件主目录
private String outFile;//输出文件目录
private String stopFile;//停止文件目录
private String fileType;//文件类型 *.java *.c *.txt
private List<String> commandSet=new ArrayList<String>();
private void setCommand() {
commandSet.add(comLine);
commandSet.add(comChar);
commandSet.add(comWord);
commandSet.add(comAdva);
commandSet.add(comBatch);
commandSet.add(filePath);//写入时固定将目录路径写在-s后面
commandSet.add(fileType);
commandSet.add(sourceFile);
commandSet.add(comE);
commandSet.add(stopFile);
commandSet.add(comO);
commandSet.add(outFile);
}
public String[] getCommand()
{
setCommand();
return (String[])commandSet.toArray(new String[0]);
}
public String getComO() {
return comO;
}
public void setComO(String comO) {
this.comO = comO;
}
public String getComE() {
return comE;
}
public void setComE(String comE) {
this.comE = comE;
}
public String getComLine() {
return comLine;
}
public void setComLine(String comLine) {
this.comLine = comLine;
}
public String getComChar() {
return comChar;
}
public void setComChar(String comChar) {
this.comChar = comChar;
}
public String getComWord() {
return comWord;
}
public void setComWord(String comWord) {
this.comWord = comWord;
}
public String getComAdva() {
return comAdva;
}
public void setComAdva(String comAdva) {
this.comAdva = comAdva;
}
public String getComBatch() {
return comBatch;
}
public void setComBatch(String comBatch) {
this.comBatch = comBatch;
}
public String getSourceFile() {
return sourceFile;
}
public void setSourceFile(String sourceFile) {
this.sourceFile = sourceFile;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getOutFile() {
return outFile;
}
public void setOutFile(String outFile) {
this.outFile = outFile;
}
public String getStopFile() {
return stopFile;
}
public void setStopFile(String stopFile) {
this.stopFile = stopFile;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
}
成果
界面展示
主界面
文件选择器
提示框
完整运行结果
https://www.cnblogs.com/kong1987/p/pairing.html
总结
这次结对编程让我意识到有些时候还是1+1>2的,就是把很多复杂的工作分离成小工作,分工合作完成的时候,效率很快,但是在完整的开发过程中有时候是1+1<2的,那就是沟通不流畅的时候,这里的沟通指的是有时候不能坐在一起沟通,只能通过沟通工具沟通的时候,能够很明显感觉到需求说不出,或者是说出了对方理解不了的情况,这也是这个项目拖延得比较久的原因,今天大部分功能完成的时候,大家坐到一起时马上就解决了之前几天遗留的问题,项目运行也完成了,还有一些逻辑的优化、界面的友好度和一些小bug可以优化,但是不影响功能的完整运行。
个人开发时遇到的问题大部分都通过查找CSDN,博客园得到了解决,也在边查找边开发的过程中学习到了Java Swing的一些用法,可惜在我界面开发完成后才发现了JavaFX这种技术,界面更美观,也更体现了面向对象的抽象封装特性,代码简洁,没有swing那么冗杂,swing简单的一个界面就有几百行代码,我看到其他同学们也有使用FX技术的,值得学习学习。
致谢
淡漠一生,何欲何求 的博客 https://www.cnblogs.com/mrdz/p/7716643.html
yongchaocsdn的博客 https://blog.csdn.net/yongchaocsdn/article/details/53355296
u010181717的博客 https://blog.csdn.net/u010181717/article/details/13000759
yanjingtp的博客 https://blog.csdn.net/yanjingtp/article/details/79282365
百度知道 https://zhidao.baidu.com/question/545174029.html
树叶子hza的博客 https://blog.csdn.net/hza419763578/article/details/80669128
以上博主的博客对我学习和使用javaSwing的帮助很大,在此衷心的感谢。