基于Java面向对象思想对个人项目的深度分析
一、摘要
本文站在java面向对象思想的角度,深入研究了GJH同学Java中小学数学卷子自动生成程序的工程代码。通过对核心类、继承与多态、封装与解耦等面向对象思想和生成题目算法进行了深度分析,全面探讨了系统的优缺点与改进空间。
关键字:java面向对象思想、算法、字符串、io流。
二、面向对象设计与实现
2.1 模块化设计与核心类
深入剖析核心类的设计:本项目以模块化设计为基础,共有Application、User、IO、Utils、Question、QuestionIml六个类,登录检查、文件操作、生成题目三大主要功能分别用不同的类实现,体现了面向对象封装思想的高内聚、低耦合的特点;Question和QuestionIml体现了继承关系的合理应用,但QuestionIml类过于臃肿,在一个类里面实现了生成小学、初中、高中题目的三种方法,从面向对象的角度分析,不利于今后的扩展和维护;同时,对于User类的定义不够精确,login()方法本应属于客户端的一个模块,却定义在了User类里。
public interface Qustion {
public void createPrimaryTests(int num);
public void createJuniorTests(int num);
public void createSeniorTests(int num);
public void generate(int level, int num);
}
三、核心算法剖析
3.1随机性与灵活性
系统通过引入随机数和种子的方法生成随机的操作数和操作符,并灵活使用字符串拼接的操作来生成题目,保证了生成的题目丰富多样。同时,通过适应不同的学科等级,实现了灵活的生成策略,使得系统具有一定的适应性和可配置性。另外,通过设计查重算法也避免了生成相同的题目,不足之处在于没有筛选掉a+b=b+a的重复题目。
for (int i = 0; i < num; i++) {
StringBuffer finalStr = new StringBuffer();
//...
//4.拼接算术符号
for (int j = 0; j < numbers - 1; j++) {
finalStr.append(operands[j] + signs[random.nextInt(4)]);
}
finalStr.append(operands[numbers - 1] + "=");
//5.判断是否重复,如果重复则重新生成
boolean isRepeated = Utils.repetitionCheck(finalStr.toString());
//...
}
3.2异常处理与健壮性
在代码中,针对用户的输入和各种可能的情况考虑到了详细的异常处理。例如,在用户登录时,通过判断输入是否合法,避免了程序崩溃或进入死循环的情况,提升了系统的健壮性;针对用户不同的命令如:切换模式、生成题目、重新登陆使用try{}catch{}结构进行异常处理。
try {
int num = Integer.parseInt(input);
if (num == -1) {
//...
} catch (NumberFormatException e) {
int levelNum = changeLevel(input);
if (levelNum != -1) {
creatingInterface(levelNum);
}
}
四、改进空间
4.1用户信息存储
在本项目中,用户账号有"张三1"-"王五3",用户规模相对较小,然而我们考虑到系统的未来拓展性与应用广度,因此可以考虑将用户的账号、密码以及用户类型等信息记录在一个独立的txt文件中。在程序运行时,通过读文件的方式获取用户信息,从而实现了对用户信息的动态管理与灵活扩展。这种设计方案不仅有助于系统的维护与扩展,也提高了系统的可用性与可维护性。
4.2题目生成方法
考虑到面向对象中的单一职责原则,涉及到小学初中高中的题目生成方法全部内聚在同一个类中,代码的代码的可维护性和扩展性较低,今后需要更改方法容易出现bug,应该将三种方法拆开,设置PrimarySchool、MiddleSchool、HighSchool三个类分别实现,这种拆分设计也符合单一职责原则,使得各个类的职责更加清晰明确。
五、详细代码分析
定义了一个generateParentheses方法,这段代码根据随机数来增加前括号和后括号并使用相应的flagKuo数组相应的元素来进行标记
定义了一个generateSpecialSigns1方法,这段代码根据随机数生成特殊符号(平方符号或平方根符号),并将它们添加到名为operands
的数组中的随机位置。同时,代码确保同一位置不会多次生成相同的特殊符号
定义了一个writeIntoTxt方法,这段代码的功能是将一组题目写入到一个文本文件中,文件的路径根据当前用户和时间动态生成。文件的内容来源于传入的questions
数组。同时,代码对文件的创建和写入过程进行了异常处理。特色在于灵活的使用到了java文件io流这种技术,有效地将数据保存到本地。并且采用了BufferedWriter类缓冲流,功能效率上比起一般的流更加地好,其类内部维护了一个缓冲区,可以一次性写入多个字符到缓冲区,减少了实际写入磁盘或网络的次数,从而提高了写入性能。
定义了一个readallTxt方法,这段代码的功能是读取一个账号下出国的所有题目,如果不存在的话先创建文件,并且使用了set容器进行查重。同时,代码对文件的创建和读入过程进行了异常处理。特色在于灵活的使用到了java文件io流这种技术,有效地将数据保存到本地。并且采用了BufferedReader类缓冲流,功能效率上比起一般的流更加地好,其类内部维护了一个缓冲区,可以一次性写入多个字符到缓冲区,减少了实际写入磁盘或网络的次数,从而提高了写入性能。
定义了一个getCurrTime方法,通过获取当前时间来创建以时间命名的txt文件
定义了一个changeLevel方法,方便用户在得到想要的题目后切换模式再一次进行出题
定义了一个creatingInterfacefangfa,这段代码的主要功能是根据用户在登陆成功以后的不同指令做出应答,并完成相应的指令,逻辑清晰的代码思路体现出了作者严谨缜密的思维,完成了所有预期的功能。
六、测试结果分析
小学题目,实现了"+、-、*、/"的题目
初中题目:带有根号或者平方的题目
高中题目:带有sin、cos、tan的题目
七、实验感受
通过本次个人项目,对学习过的面向对象这门课有了更加真切的感受,在编程的过程中对于面向对象的封装、继承、多态有了更好的体会,并且也在这次动手实验编程的过程中熟悉了java的更多操作比如字符串、io流相关的知识。在项目过程中遇到不同的 新的问题、挑战,我们要时刻保持积极乐观的态度去面对,这样才能更好地提升我们自己的水平。
八、代码原件
8.1QuestionImpl源代码
public class QustionImpl implements Qustion { String[] signs = {"+", "-", "*", "/"}; String[] operands; /** * 对应位置是否包含括号,只有同时包含才非法 */ boolean[] flagsKuo; /** * 对应位置是否有拼音 */ boolean[] flagsPingfang; /** * 对应位置是否有根号 */ boolean[] flagsGeng; /** * 对应位置是否有三角函数 */ boolean[] flagsTrigonometricFunc; Random random = new Random(); @Override public void generate(int level, int num) { switch (level) { case 0: this.createPrimaryTests(num); break; case 1: this.createJuniorTests(num); break; case 2: this.createSeniorTests(num); break; default: } } @Override public void createPrimaryTests(int num) { // 使用当前时间作为随机种子,避免生成的序列相同 long seed = System.currentTimeMillis(); random.setSeed(seed); String[] strs = new String[num]; for (int i = 0; i < num; i++) { StringBuffer finalStr = new StringBuffer(); //操作数个数 int numbers = random.nextInt(4) + 2; operands = new String[numbers]; flagsKuo = new boolean[numbers]; //1.生成操作数 for (int j = 0; j < numbers; j++) { //生成1-100的数字 operands[j] = String.valueOf(random.nextInt(100) + 1); } //2.生成括号,长度>=3才生成 if (numbers >= 3) { generateParentheses(numbers); } //3.拼接算术符号 for (int j = 0; j < numbers - 1; j++) { finalStr.append(operands[j] + signs[random.nextInt(4)]); } finalStr.append(operands[numbers - 1] + "="); //4.判断是否重复,如果重复则重新生成 boolean isRepeated = Utils.repetitionCheck(finalStr.toString()); if (isRepeated) { System.out.println("题目重复"); i--; continue; } strs[i] = "题目" + (i + 1) + " : " + finalStr.toString(); } //写入txt Io.writeIntoTxt(strs); } @Override public void createJuniorTests(int num) { // 使用当前时间作为随机种子,避免生成的序列相同 long seed = System.currentTimeMillis(); random.setSeed(seed); String[] strs = new String[num]; for (int i = 0; i < num; i++) { StringBuffer finalStr = new StringBuffer(); //操作数个数 int numbers = random.nextInt(5) + 1; operands = new String[numbers]; flagsKuo = new boolean[numbers]; flagsPingfang = new boolean[numbers]; flagsGeng = new boolean[numbers]; //1.生成操作数 for (int j = 0; j < numbers; j++) { operands[j] = String.valueOf(random.nextInt(100) + 1); } //2.生成根号、平方 generateSpecialSigns1(numbers); //3.生成括号,长度>=3才生成 if (numbers >= 3) { generateParentheses(numbers); } //4.拼接算术符号 for (int j = 0; j < numbers - 1; j++) { finalStr.append(operands[j] + signs[random.nextInt(4)]); } finalStr.append(operands[numbers - 1] + "="); //5.判断是否重复,如果重复则重新生成 boolean isRepeated = Utils.repetitionCheck(finalStr.toString()); if (isRepeated) { System.out.println("题目重复"); i--; continue; } strs[i] = "题目" + (i + 1) + " : " + finalStr.toString(); } Io.writeIntoTxt(strs); } //生成num个高中题目 @Override public void createSeniorTests(int num) { long seed = System.currentTimeMillis(); random.setSeed(seed); String[] strs = new String[num]; for (int i = 0; i < num; i++) { StringBuffer finalStr = new StringBuffer(); int numbers = random.nextInt(5) + 1; operands = new String[numbers]; flagsKuo = new boolean[numbers]; flagsPingfang = new boolean[numbers]; flagsGeng = new boolean[numbers]; flagsTrigonometricFunc = new boolean[numbers]; for (int j = 0; j < numbers; j++) { operands[j] = String.valueOf(random.nextInt(100) + 1); } //2.生成三角函数 generateTrigonometricFunc(numbers); //3.生成平方、根号 generateSpecialSigns1(numbers); //4.生成括号,长度>=3才生成 if (numbers >= 3) { generateParentheses(numbers); } //5.拼接算术符号 for (int j = 0; j < numbers - 1; j++) { finalStr.append(operands[j] + signs[random.nextInt(4)]); } finalStr.append(operands[numbers - 1] + "="); //6.判断是否重复,如果重复则重新生成 boolean isRepeated = Utils.repetitionCheck(finalStr.toString()); if (isRepeated) { System.out.println("题目重复"); i--; continue; } strs[i] = "题目" + (i + 1) + " : " + finalStr.toString(); } Io.writeIntoTxt(strs); } /** * 生成括号,参数为:操作数个数 生成原则,操作数个数>=3时生成,个数为1至numbers-2;生成一个长度2<=len<=numbers-1 * 起始位置:start<numbers-len,这样结束位置<=start+len<numbers 注意,生成(号前,该位置不能有); 生成)号前,该位置不能有( * * @param numbers */ public void generateParentheses(int numbers) { //个数为1至numbers-2 int kuohaoNums = random.nextInt(numbers - 2) + 1; while (kuohaoNums > 0) { //生成一个长度2<=len<=numbers-1 int len = random.nextInt(numbers - 2) + 2; int start = random.nextInt(numbers - len), end = start + len - 1; //如果首尾重复了,则生成失败 if (flagsKuo[start] && flagsKuo[end]) { kuohaoNums--; continue; } operands[start] = "(" + operands[start]; operands[end] += ")"; //设置标记,已经加过括号了 flagsKuo[start] = true; flagsKuo[end] = true; kuohaoNums--; } } /** * 生成平方和根号,最多生成numbers个(限制难度) * * @param numbers */ public void generateSpecialSigns1(int numbers) { int totals = random.nextInt(numbers) + 1; for (int i = 0; i < totals; i++) { int position = random.nextInt(numbers); //一半概率生成平方,并且他之前没生成过平方 if (random.nextBoolean()) { if (!flagsPingfang[position]) { operands[position] += "²"; flagsPingfang[position] = true; } else { continue; //重复了,继续 } } else { if (!flagsGeng[position]) { operands[position] = "√" + operands[position]; flagsGeng[position] = true; } else { continue; //重复了,继续 } } } } /** * 生成三角函数,最多生成numbers-1个,并且同一位置不重复生成(限制难度) * * @param numbers */ public void generateTrigonometricFunc(int numbers) { int totals = random.nextInt(numbers); for (int i = 0; i < totals; i++) { int position = random.nextInt(numbers); int state = random.nextInt(3); //生成sin if (state == 0 && !flagsTrigonometricFunc[position]) { operands[position] = "sin" + operands[position]; flagsTrigonometricFunc[position] = true; } //生成cos else if (state == 1 && !flagsTrigonometricFunc[position]) { operands[position] = "cos" + operands[position]; flagsTrigonometricFunc[position] = true; } //生成tan else if (state == 2 && !flagsTrigonometricFunc[position]) { operands[position] = "tan" + operands[position]; flagsTrigonometricFunc[position] = true; } } } }
标签:Java,int,生成,面向对象,num,numbers,深度,new,finalStr From: https://www.cnblogs.com/Protsin/p/17720481.html