前三次PTA作业总结

Posted zhuzexi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前三次PTA作业总结相关的知识,希望对你有一定的参考价值。

------------恢复内容开始------------
一、作业总结
我们总共进行了三次题目集的练习,无论是题目量,题目难度还是知识点,都是逐步递增的,并且越进行到后面的题目,运用到的技术也越来越多,在一周内(并且还有其他的课业的情况下)完成还是颇具难度的。

第一次题目集总体难度并不大,主要考察的是对输入输出最基本的运用,更多的还是面向过程的运用,只有最后一题判断三角形需要考虑的多一点。

第二次题目集相比与第一次,难度就有着一定的提升了,第二次的四题开始考察类与方法的运用,慢慢开始有着面向对象的影子了。

第三次题目的难度与前两次相比,难度就开始直线上升了,代码的耦合度开始迅速上升,开始运用继承,多态以及接口等,对于这次题目,我也想了很久才做出来,期中遇到的问题也是最多的,调试测试点的过程也是很痛苦,不过好在最后也是成功钻研了出来。

二、设计与分析

主要分析菜单计价程序1,菜单计价程序2和菜单计价程序3:

菜单计价程序一
菜品类:对应菜谱上一道菜的信息。
Dish
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)

菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu
Dish[] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。

点菜记录类:保存订单上的一道菜品记录
Record
Dish d;//菜品
int portion;//份额(1/2/3代表小/中/大份)
int getPrice()//计价,计算本条记录的价格

订单类:保存用户点的所有菜的信息。
Order
Record[] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(String dishName,int portion)
//添加一条菜品信息到订单中。

输入格式:
每条点菜记录的格式:
菜名+空格(英文)+份额
注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
最后一条记录以“end”结束。

输出格式:
订单上所有菜品的总价(整数数值),每份菜
如果订单中包含不能识别的菜名,则在总价之前输出“ does not exist”,是不能识别的菜名

类图

方法图

菜单计价系统1:main函数通过调用 菜品类Dish 菜谱类Menu 点菜记录类Record 订单类Order 4个类来完成相应功能,然后创建一个菜谱对象和一个订单对象,接受的一整行的输入,将这一行沿空格进行分割,将相应的份数转换为浮点数,再将点菜的菜名与菜谱对象进行比较,检查对应的菜名,

运行结果如下:

代码如下:import java.util.*;
import java.util.Scanner;

// 菜品类
class Dish
String name; // 菜品名称
int unit_price; // 单价

Dish(String name, int unit_price) 
    this.name = name;
    this.unit_price = unit_price;


// 计算菜品价格的方法
int getPrice(int portion) 
    double price = unit_price;
    if (portion == 2) 
        price *= 1.5;
     else if (portion == 3) 
        price *= 2;
    
    return (int) Math.round(price);

// 菜谱类
class Menu
Dish[] dishes; // 菜品数组,保存所有菜品信息

// 构造函数
Menu(Dish[] dishes) 
    this.dishes = dishes;


// 根据菜名在菜谱中查找菜品信息
Dish searchDish(String dishName) 
    for (Dish dish : dishes) 
        if (dish.name.equals(dishName)) 
            return dish;
        
    
    return null;

// 点菜记录类
class Record
Dish dish; // 菜品
int portion; // 份额(1/2/3代表小/中/大份)

// 构造函数
Record(Dish dish, int portion) 
    this.dish = dish;
    this.portion = portion;


// 计价,计算本条记录的价格
int getPrice() 
    return dish.getPrice(portion);

// 订单类
class Order
List records; // 保存订单上每一道的记录

// 构造函数
Order() 
    this.records = new ArrayList<>();





Record addARecord(String dishName, int portion, Menu menu) 
    Dish dish = menu.searchDish(dishName);
    if (dish == null) 
        System.out.println(dishName + " does not exist");
        return null;
    
    Record record = new Record(dish, portion);
    records.add(record);
    return record;



int getTotalPrice() 
    int totalPrice = 0;
    for (Record record : records) 
        totalPrice += record.getPrice();
    
    return totalPrice;

// 主函数
public class Main
public static void main(String[] args)
// 创建菜谱
Dish[] dishes =
new Dish("西红柿炒蛋", 15),
new Dish("清炒土豆丝", 12),
new Dish("麻婆豆腐", 12),
new Dish("油淋生菜", 9)
;
Menu menu = new Menu(dishes);

    // 创建订单
    Order order = new Order();

    // 读取点菜记录
    Scanner scanner = new Scanner(System.in);
    while (true) 
        String line = scanner.nextLine();
        if (line.equals("end")) 
            break;
        
        String[] parts = line.split(" ");
        String dishName = parts[0];

        int portion = Integer.parseInt(parts[1]);
        order.addARecord(dishName, portion, menu);
    

    // 输出总价
    System.out.println(order.getTotalPrice());

菜单计价系统二:
设计点菜计价程序,根据输入的信息,计算并输出总价格。

输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。

菜单由一条或多条菜品记录组成,每条记录一行

每条菜品记录包含:菜名、基础价格 两个信息。

订单分:点菜记录和删除信息。每一类信息都可包含一条或多条记录,每条记录一行。
点菜记录包含:序号、菜名、份额、份数。
份额可选项包括:1、2、3,分别代表小、中、大份。

删除记录格式:序号 delete

标识删除对应序号的那条点菜记录。

不同份额菜价的计算方法:
小份菜的价格=菜品的基础价格。
中份菜的价格=菜品的基础价格1.5。
小份菜的价格=菜品的基础价格2。
如果计算出现小数,按四舍五入的规则进行处理。

参考以下类的模板进行设计:
菜品类:对应菜谱上一道菜的信息。

Dish
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。

Menu
Dish[] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
Dish addDish(String dishName,int unit_price)//添加一道菜品信息

点菜记录类:保存订单上的一道菜品记录

Record
int orderNum;//序号
Dish d;//菜品
int portion;//份额(1/2/3代表小/中/大份)
int getPrice()//计价,计算本条记录的价格

订单类:保存用户点的所有菜的信息。

Order
Record[] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。
delARecordByOrderNum(int orderNum)//根据序号删除一条记录
findRecordByNum(int orderNum)//根据序号查找一条记录

输入格式:
菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:
序号+英文空格+菜名+英文空格+份额+英文空格+份数
注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete

最后一条记录以“end”结束。

输出格式:
按顺序输出每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品*份数,序号是之前输入的订单记录的序号。
如果订单中包含不能识别的菜名,则输出“** does not exist”,**是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后输出订单上所有菜品的总价(整数数值),

UML图如下:

运行结果如下:

代码如下:
import java.util.Scanner;
public class Main
public static void main(String[] args)
Scanner input = new Scanner(System.in);
Menu menu = new Menu();
Order order = new Order();
Tranform tranform = new Tranform();
String s;
String name;
int price;
int portion;
int id;
int a;
int dishsum;
while(true)
s = input.nextLine();
String[] split = s.split(" "); //分割符操作
if(split[0].equals("end"))
break;

a = tranform.getsize(split);
if(a1)
name = split[0];
price = Integer.parseInt(split[1]);
menu.addDish(name,price);

else if(a
2)
id = Integer.parseInt(split[0]);
name = split[1];
portion = Integer.parseInt(split[2]);
dishsum = Integer.parseInt(split[3]);
Dish dish = menu.searthDish(name);
if(dishnull)
System.out.println(name+" does not exist");

else
System.out.println(id+" "+name+" "+dish.getprice(portion,dishsum));
order.addARecord(id,dish,portion,dishsum);//添加订单


else if(a
3)
id = Integer.parseInt(split[0]);
Record record = order.findRecordByNum(id);
if (record == null)
System.out.println("delete error");
else
order.delARecordByOrderNum(id);



int sum=0;
sum= order.getTotalPrice(); //计算总和
System.out.println(sum);

class Dish
String name;//菜品名称
int price; //单价
public Dish(String name,int price)
this.name = name;
this.price = price;

public int getprice(int portion,int dishsum)
if(portion1)
return price*dishsum;

else if(portion
2)
int Iprice = (int) (price1.5);
if(price-Iprice>=0.5)
return (Iprice+1)
dishsum;

else
return Ipricedishsum;


else if(portion==3)
return price
2*dishsum;

return 0;
//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份;

class Menu

Dish[] dishs = new Dish[100];

public Dish searthDish(String dishName)
    for(int i=0;i<dishs.length;i++) 
        if(dishs[i]!=null && dishs[i].name.equals(dishName)) 
            return dishs[i];
        
    
    return null;

public Dish addDish(String dishName,int price)
    Dish dish = new Dish(dishName,price);
    for(int i=0;i<dishs.length;i++)
        if(dishs[i]==null)
            dishs[i] = dish;
            break;
        
    
    return dish;

class Order
Record[] records = new Record[100];//保存订单上每一道的记录
public int getTotalPrice()
int sum = 0;
for(int i=0;i<records.length;i++)
if(records[i]!=null)
records[i].getPrice();
sum+=records[i].getPrice();


return sum;

public Record addARecord(int id,Dish dish,int portion,int dishsum)
//Menu menu = new Menu();
//Dish dish = menu.searthDish(dishName);
Record record = new Record(dish,portion,dishsum);
records[id] = record;
return record;

//添加一条菜品信息到订单中。
public Record findRecordByNum(int id)
return records[id];

public Record delARecordByOrderNum(int id)
records[id]=null;
return null;

class Record
int dishsum;
Dish d;//菜品
int portion;//份额(1/2/3代表小/中/大份)
public Record(Dish dish, int portion,int dishsum)
this.dishsum = dishsum;
this.d=dish;
this.portion=portion;

int getPrice()
int price = d.getprice(portion,dishsum);
return price;
//计价,计算本条记录的价格

class Tranform
public int getsize(String[] split)
String id = split[0];
String[] arr = "1", "2", "3", "4", "5", "6", "7", "8", "9";
for (int i = 0; i < 9; i++)
if (id.substring(0, 1).equals(arr[i]))
String cd = split[1];
if (cd.equals("delete"))
return 3;
else
return 2;



return 1;

菜单计价系统三:
设计点菜计价程序,根据输入的信息,计算并输出总价格。

输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。

菜单由一条或多条菜品记录组成,每条记录一行

每条菜品记录包含:菜名、基础价格 两个信息。

订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。

桌号标识独占一行,包含两个信息:桌号、时间。

桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。

点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。

不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。

删除记录格式:序号 delete

标识删除对应序号的那条点菜记录。

如果序号不对,输出"delete error"

代点菜信息包含:桌号 序号 菜品名称 份额 分数

代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。

程序最后按输入的先后顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。

每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。

折扣的计算方法(注:以下时间段均按闭区间计算):

周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。

周末全价,营业时间:9:30-21:30

如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours"

参考以下类的模板进行设计:菜品类:对应菜谱上一道菜的信息。

Dish

String name;//菜品名称

int unit_price; //单价

int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)

菜谱类:对应菜谱,包含饭店提供的所有菜的信息。

Menu

Dish[] dishs ;//菜品数组,保存所有菜品信息

Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。

Dish addDish(String dishName,int unit_price)//添加一道菜品信息

点菜记录类:保存订单上的一道菜品记录

Record

int orderNum;//序号\\

Dish d;//菜品\\

int portion;//份额(1/2/3代表小/中/大份)\\

int getPrice()//计价,计算本条记录的价格\\

订单类:保存用户点的所有菜的信息。

Order

Record[] records;//保存订单上每一道的记录

int getTotalPrice()//计算订单的总价

Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。

delARecordByOrderNum(int orderNum)//根据序号删除一条记录

findRecordByNum(int orderNum)//根据序号查找一条记录

输入格式:

桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete

代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数

最后一条记录以“end”结束。

输出格式:

按输入顺序输出每一桌的订单记录处理信息,包括:

1、桌号,格式:table+英文空格+桌号+”:”

2、按顺序输出当前这一桌每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“** does not exist”,**是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价

本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。

输入格式:
桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete

代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数

最后一条记录以“end”结束。

输出格式:
按输入顺序输出每一桌的订单记录处理信息,包括:

1、桌号,格式:table+英文空格+桌号+“:”+英文空格

2、按顺序输出当前这一桌每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“** does not exist”,**是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价

UML图:
首先引入一个时间类:

import java.time.LocalDateTime;
以下是time类代码:

class Time
String time1;
String time2;
int year;
int month;
int day;
int hour;
int minute;
int weekday;
void getWeekday()

this.weekday= LocalDateTime.of(this.year,this.month,this.day,this.hour,this.minute).getDayOfWeek().getValue();

void getYear()

String [] k=time1.split("\\/");
year=Integer.parseInt(k[0]);
month=Integer.parseInt(k[1]);
day=Integer.parseInt(k[2]);

void getDay()

String[] k = time2.split("\\/");
hour=Integer.parseInt(k[0]);
minute=Integer.parseInt(k[1]);

这里的时间类就是将传入的字符串按顺序分割,获得是在星期几的几点。然后在table里计算价格的时候使用。

以下为table类代码:

class Table

int num;
Time time=new Time();
Order order=new Order();
int tablePrice;void getPrice()

    time.getDay();
    time.getYear();
    time.getWeekday();
    if(time.weekday<=5&&time.weekday>=1)
    
        if((time.hour>=17&&time.hour<20)||(time.hour==20&&time.minute<=30))
        
            tablePrice=(int)Math.round(order.getTotalPrice()*0.8);
            System.out.print("table "+this.num+": "+this.tablePrice+" ");
        
        else if((time.hour==10&&time.minute>=30)||(time.hour>=11&&time.hour<14)||(time.hour==14&&time.minute<=30))
        
            tablePrice=(int)Math.round(order.getTotalPrice()*0.6);
            System.out.print("table "+this.num+": "+this.tablePrice+" ");
        
        else System.out.println("table "+this.num+" out of opening hours");
    
    if(time.weekday==6||time.weekday==7)
    
        if((time.hour==9&&time.minute>=30)||(time.hour>9&&time.hour<21)||(time.hour==21&&time.minute<=30))
        
            tablePrice=(int)Math.round(order.getTotalPrice());
            System.out.print("table "+this.num+": "+this.tablePrice+" ");

        
        else System.out.println("table "+this.num+" out of opening hours");
    

这里我在获得价格的同时直接输出结果(对获得的时间进行判断然后计算相应折扣),所以在主函数直接调用就行,而且这里一个桌子就代表着一个订单,则在内部再定义一个order类。还有一个桌号的属性。

主函数main就需要重新写过,因为每个字符串的长度发生了变化,所以出现的情况会有所不同,main函数代码如下:

public static void main(String[] args)

    Scanner sc=new Scanner(System.in);
    Table[] table=new Table[10];
    Menu menu=new Menu();
    int i=0;
    String str=sc.nextLine();
    while(!str.equals("end"))
    
        String[] data = str.split(" ");
        if(data.length==2&&!data[1].equals("delete"))
        
            menu.add(data[0],Integer.parseInt(data[1]));
        
        if(data.length==4&&data[0].equals("table"))
        
            i++;
            table[i]=new Table();
            table[i].order=new Order();
            table[i].order.menu=menu;
            table[i].num=Integer.parseInt(data[1]);
            table[i].time.time1=data[2];
            table[i].time.time2=data[3];
            System.out.println("table "+Integer.parseInt(data[1])+":");
        
        if(data.length==4&&!data[0].equals("table"))
        
            if(menu.searthDish(data[1])!=null)
            
                table[i].order.addARecord(Integer.parseInt(data[0]), data[1], Integer.parseInt(data[2]), Integer.parseInt(data[3]));
                Dish d = new Dish();
                d=menu.searthDish(data[1]);
                System.out.println(data[0]+" "+data[1]+" "+d.getPrice(Integer.parseInt(data[2]))*Integer.parseInt(data[3]));
            
            else if(menu.searthDish(data[1])==null)
            
                System.out.println(data[1]+ " does not exist");
            
        
        if(data.length==5)
        
            if(menu.searthDish(data[2])!=null)
            
                table[i].order.addARecord(Integer.parseInt(data[1]),data[2],Integer.parseInt(data[3]),Integer.parseInt(data[4]));
                Dish d = new Dish();
                d=menu.searthDish(data[2]);
                System.out.println(data[1]+" "+"table"+" "+table[i].num+" pay for table "+data[0]+" "+d.getPrice(Integer.parseInt(data[3]))*Integer.parseInt(data[4]));
            
            else if(menu.searthDish(data[2])==null)
            
                System.out.println(data[2]+ " does not exist");
            
        
        if(data.length==2&&data[1].equals("delete"))
        
            table[i].order.delARecordByOrderNum(Integer.parseInt(data[0]));
        
        str=sc.nextLine();
    
    for(int num=1;num<=i;num++)
    
        table[num].getPrice();
    
    sc.close();

由于第三次的类图与uml图较为混乱且有缺陷,在此就不做展示了。

三、踩坑心得
在实现第三道题目中,最困难的是维护数量不确定的订单中的菜品,特别是在添加订单记录时需要动态地增加记录,在Java中可以使用数组实现。同时,在写查询单个菜品的接口时,
需要注意到可能返回null值的情况,必须进行判断以避免程序崩溃。除此之外,整个程序的设计并没有太大的问题,实现起来比较顺畅。

在写代码时,最重要的是规划,如果一个for循环就可以解决的问题,不必用更多的for循环而导致运行超时。
四、主要困难与踩坑建议

应让代码更加符合规范。此外,尽可能的将方法简化,将重复代码提出,减少重复代码,提高代码的复用性。
SouranceMonitor的生成报表图可知,有简单明了的注释,在自己写代码的过程中也能够让自己读懂,方便前后增添、修改代码。除代码的注释外,对变量的命名也要规范,要使用简单易懂,具有意义的名称,使代码易于理解与维护。

五、总结
java中的已经定义的类是非常多的,仅仅是写题目的时候用一次只能有一个粗略映像,需要花其他时间去巩固。此外,在写题目时,不要急于求成,也不要不带脑子写代码,使得写出的代码不仅得分不高,质量还低

OO前三次作业总结

第一次作业

 技术分享图片

第二次作业

 技术分享图片

第三次作业 

 技术分享图片

 自我剖析

       三次作业实现过程非常简单,公测全过,互测也未发现bug,就实现结果而言可以接受,但是在面向对象的思想实现上有所欠缺、代码可读性较差,也未使用正则表达式,仍待改进。

互测策略

       根据指导书所描述的任务需求、规则构造相应极端数据,对被测者代码进行黑盒测试。前两次测试任务程序均比较完美,公测全过,除第二次手中程序作者在指导书理解上出现遗漏导致bug产生外无其余bug;第三次测试任务公测未过同质判断测试点,经过构造数据找到程序五个bug。

心得体会

       通读指导书、勤发问,多多查阅资料,认真思考,以一颗积极的心面对每一次作业,往往能起到事半功倍的效果。

------熬夜是不可能熬夜的,这学期都不可能熬夜的

以上是关于前三次PTA作业总结的主要内容,如果未能解决你的问题,请参考以下文章

第三次Blog作业

OO前三次作业总结

点菜系列总结

OO第四次作业——前三次作业总结

关于三次pta大作业的总结报告

OO第四次作业-对前三次作业总结