结对项目代码分析

一、项目需求:

用户:

小学、初中和高中数学老师。

功能:

1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为小学、初中和高中三个选项中的一个。否则提示“请输入正确的用户名、密码”,重新输入用户名、密码;

2、登录后,系统提示“准备生成XX数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”,XX为小学、初中和高中三个选项中的一个,用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。每道题目的操作数在1-5个之间,操作数取值范围为1-100;

3、题目数量的有效输入范围是“10-30”(含10,30,或-1退出登录),程序根据输入的题目数量生成符合小学、初中和高中难度的题目的卷子(具体要求见附表)。同一个老师的卷子中的题目不能与以前的已生成的卷子中的题目重复(以指定文件夹下存在的文件为准,见5);

4、在登录状态下,如果用户需要切换类型选项,命令行输入“切换为XX”,XX为小学、初中和高中三个选项中的一个,输入项不符合要求时,程序控制台提示“请输入小学、初中和高中三个选项中的一个”;输入正确后,显示“”系统提示“准备生成XX数学题目,请输入生成题目数量”,用户输入所需出的卷子的题目数量,系统新设置的类型进行出题;

5、生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文件夹。每道题目有题号,每题之间空一行;

 

 

 二、代码分析

代码分析:

首先创建了一个teacher类,包含教师的用户名,密码,类型,以及文件夹路径。

里面有三个方法:

第一个方法是login,用来登录用户且为新教师创建文件夹:

    def login(self):

        inputId = input()

        inputPassword = input()

        filename = 'teachertable.txt'

        messdict = {}

        print(1)

        with open(filename, encoding='utf-8') as file_object:

            for line in file_object:

                line = line.rstrip()

                list1 = line.split(' ')

                list2 = []

                list2.append(list1[1])

                list2.append(list1[2])

                messdict[list1[0]] = list2

        while 1:

            if inputId in messdict:

                if messdict[inputId][0] == inputPassword:

                    print("当前选择为"+messdict[inputId][1]+"出题")

                    self.id = inputId

                    self.password = inputPassword

                    self.type = messdict[inputId][1]

                    break

            print("请输入正确的用户名、密码")

            inputId = input()

            inputPassword = input()

        self.folderpath = '.\\tests\\'+inputId

        if not os.path.isdir(self.folderpath):

            os.mkdir(self.folderpath)

第二个方法是生成试卷的generateTest方法

    def generatTest(self):

        num1 = input("准备生成"+self.type+"数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):")

        num = int(num1)

        while (num > 30) | (num < 10):

            if num != -1:

                num = input("题目数量无效,请重新输入:")

            else:

                print("重新登录", end=" ")

                self.login()

                break

        print("正在生成题目,请稍后")

 

        #新建文件

        filename = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())

        filename += ".txt"

        fullPath = self.folderpath + "\\" + filename

        file = open(fullPath, "w+")

 

 

        operandList = ['+', '-', '*', '/'] #加减乘除列表

        juList = ['√', '^2']

        question = ""                       #题目字符串

        while num != 0:

            opnum = random.randint(1, 4) #操作数数量

            oplist = []

            firstOperandNum = random.randint(1, 100) #第一个操作数

            questionList = []

            #为小学出题

 

            questionList.append(str(firstOperandNum))

            for i in range(0, opnum):

                tmp = random.randint(0, 3)   #确定加减乘除

                operandNum = random.randint(1, 100) #随机生成一个操作数

                questionList.append(operandList[tmp])  #向题目添加操作

                questionList.append(str(operandNum))        #向题目添加操作数

 

            if self.type == "初中":

               flag1 = 0

               for j in range(0, opnum):

                    tmp1 = random.randint(0, 2)

                    if tmp1 == 0:

                        questionList[2*j] = juList[0] + questionList[2*j]

                        flag1 = 1

                    elif tmp1 == 1:

                        questionList[2 * j] = questionList[2 * j] + juList[1]

                        flag1 = 1

               if flag1 == 0:

                   j = random.randint(0, opnum-1)

                   tmp1 = random.randint(0, 1)

                   if tmp1 == 0:

                       questionList[2 * j] = juList[0] + questionList[2 * j]

                   elif tmp1 == 1:

                       questionList[2 * j] = questionList[2 * j] + juList[1]

            elif self.type == "高中":

 

                flag1 = 0

                for j in range(0, opnum):

                    tmp1 = random.randint(0, 2)

                    if tmp1 == 0:

                        questionList[2 * j] = juList[0] + questionList[2 * j]

                        flag1 = 1

                    elif tmp1 == 1:

                        questionList[2 * j] = questionList[2 * j] + juList[1]

                        flag1 = 1

                if flag1 == 0:

                    j = random.randint(0, opnum - 1)

                    tmp1 = random.randint(0, 1)

                    if tmp1 == 0:

                        questionList[2 * j] = juList[0] + questionList[2 * j]

                    elif tmp1 == 1:

                        questionList[2 * j] = questionList[2 * j] + juList[1]

 

                flag2 = 0

                for k in range(0, opnum):

                    tmp2 = random.randint(0, 3)

                    if tmp2 == 0:

                        questionList[2 * k] = "sin" + questionList[2 * k]

                        flag2 = 1

                    elif tmp2 == 1:

                        questionList[2 * k] = "cos" + questionList[2 * k]

                        flag2 = 1

                    elif tmp2 == 2:

                        questionList[2 * k] = "tan" + questionList[2 * k]

                        flag2 = 1

                if flag2 == 0:

                    j = random.randint(0, opnum - 1)

                    tmp2 = random.randint(0, 2)

                    if tmp2 == 0:

                        questionList[2 * k] = "sin" + questionList[2 * k]

                    elif tmp2 == 1:

                        questionList[2 * k] = "cos" + questionList[2 * k]

                    elif tmp2 == 2:

                        questionList[2 * k] = "tan" + questionList[2 * k]

            for im in questionList:

                question += im

            filename1 = os.listdir(self.folderpath)

            flagcheck = 0

            for tmpfile in filename1:

                with open(tmpfile) as tmptest:

                    for line in tmptest :

                        print(line)

                        print(question)

                        if line == question:

                            flagcheck = 1

                            break

                if flagcheck == 1:

                    break

 

            if flagcheck == 0:

                question += '\n'

                file.write(question + '\n')

                num = num-1

 

            question = ""

第三个方法是修改用户类型的typeSwitcher方法

    def typeSwitcher(self, type1):

        while 1 :

            if type1 == "小学":

                self.type = "小学"

                break;

            elif type1 == "初中":

                self.type = "初中"

                break;

            elif type1 == "高中":

                self.type = "高中"

                break;

            elif type1 == 'n':

                break;

            print("请输入正确的选项")

        print("类型切换成功")

三、代码优缺点分析

(一)优点分析

  1. 用文本文档存储用户信息,方便修改用户,在代码中用字典临时读取存储用户信息,修改方便,后续若有大量用户需求可迁移数据
  2. 文件路径使用相对路径,绝对路径会使系统重用性差,相对路径让软件更容易迁移,提高了代码的健壮性。教师文件夹是在工程文件的tests文件夹里建立的,每个教师类都有自己的文件夹路径
  3. 题目生成的逻辑清晰,采用先生成操作数再生成操作的方式,用随机生成的通用操作来连接操作数,用列表按顺序来保存题目的操作数和操作,对于初高中的特殊字符,则向列表中添加操作元素即可。
  4. 代码中变量命名采取驼峰命名法,比较规范。
  5. 每一步的提示语都清楚明了,让用户即使输错了也会有相应的提示语句,不用担心输错而使程序终止

(二)缺点分析

  1. 生成的题目中没有括号,四则运算优先级没有考察到,题目的基本需求没有完全实现。
  2. 代码还有很多可以优化的空间,一些代码还可以写成函数调用,没有实现封装,代码的安全性有待提高,项目可以更加规范。
  3. 信息的输出方式较简陋,没有对输出的界面内容进行美化处理,例如加边框或居中等,可以采用文件流的方式美化UI
  4. 代码的耦合度较高,一旦需要修改代码则会需要重新编译所有,不利于后续的更新迭代,实现功能的变化或增加。
  5. 关于Google代码规范的很多要求并没有实际实现,希望搭档可以继续好好学习。

四、总结与心得

斯达迪 9:18:56
优点:
1、代码模块结构清晰
李牧宇同学将整个工程总体分为三个类:用户类、题目类和试卷类,实现了用户的数据保存模块,出对应小学/初中/高中难度题目的业务模块,以及生成的整张试卷的核心模块。在每个模块中对各个方法进行封装实现功能。
2、变量命名清晰规范,较好的遵循了编码规则。代码旁的注释简单明了,方便阅读,代码可读性高。
3、文件路径使用相对路径。文件路径具有相对路径和绝对路径两种形式,而绝对路径可能会使得程序的可重用性差,使得在别的终端上不能运行,而在程序中使用相对路径则会变的有极强的适应性,提高了代码健壮性。
4、交互性好
每一步的提示语都清楚明了,让用户即使输错了也会有相应的提示语句,不用担心输错而使程序终止
5、题目类核心逻辑清晰,设计巧妙。题目采用了数值与符号分离的方法来生成题目。先生成随机的操作数和具体的数值,之后以随机的通用符号连接数值。对于初高中的特有字符,选择将例如三角函数等特殊字符与数值绑定,存于数值所在的string数组中。在最后,通过逻辑加上括号运算。代码简单,逻辑清晰。

缺点:
1. UI界面并未单独成为一类,而是在主类试卷类中,高内聚低耦合,可能为后续的修改或迭代增加负担,需要重新编译,同时代码安全性可能得不到保障。
2、一次输出信息较多,但没有对输出的界面内容进行美化处理,例如加边框或居中等,可以采用文件流的方式美化UI
3、账号采用的是直接String[]存储,这就导致如果需要添加用户则需要修改代码,不利于交互与拓宽用户,可以使用数据库进行处理。

总结:

队友的代码为教师创建了一个类,并将各种功能在类的成员方法里实现了,加上注释代码,可读性还是不错的;但是生成的题目中没有括号,可能是漏看了设计要求,并没有实现所有的需求,希望下次注意。同时希望搭档可以多多注意代码规范,好好上课学习一下。同时在做设计时,也可以多多考虑一些关于安全性或者后续迭代的事情,这样在设计类的时候可能会更加合理。总的来说,虽然本次我们两人选择的代码语言并不一样,但是在互相看代码的过程中,我们彼此都触发了新的思路,新的想法,同时也收获很多,期待结对项目的合作。





 

posted @ 2022-09-14 13:03  李牧宇  阅读(87)  评论(0编辑  收藏  举报