前言:
在今年刚开始的时候,我们学习了JAVA面向对象程序设计,首先,我先了解了JAVA是一门怎样的编程语言。了解了它具有可移植性、安全性、高效性、简单性等特点,被广泛应用于企业级Web应用开发、移动应用开发、游戏开发、嵌入式系统开发等领域。首先先了解了它应该有的具体的特点。可移植性:Java程序可以在不同的操作系统和硬件平台上运行,而不需要重新编写代码。安全性:Java有一个安全模型,可以保证程序不会对系统造成损害。简单性,JAVA语言简单易懂,易于学习和使用。然后我们进行了学习与练习,主要练习了一个迭代的题目,点菜系列。主要还是学习了JAVA的基本的语法跟面向对象的特别于其他编程语言的特点。首先是用JAVA的基本语法写了一些简单的习题用来回顾和复习JAVA原因跟其他面向过程的编程语言共同之处,然后从JAVA语言的特点开始,学习了JAVA面向对象编程的特点封装、继承、多态、类、接口以及抽象类的学习。然后就是训练题目的点菜习题,难度较大,不易操作,需要用一定的时间才能够完成作业。下面主要分析三道点菜题目。
设计与分析:
第一道点菜题目的类图:

答题思路:首先进行写类图,通过类图的里面写的属性与方法,逐步加入进去,然后在主函数里面对象实例化来写一些东西来。
代码分析:
以上的类是把每一道菜的属性跟方法写出来,把菜肴的价格从主函数里面调用得到写出来。
class Menu{
public Dish[] dishs;//菜品数组,保存所有菜品信息
public void add(Dish dish)
{
int In = 0;
if(dishs!=null)
In = dishs.length;
Dish[] tmp = new Dish[In+1];
if(In>0)
{
System.arraycopy(dishs,0,tmp,0,In);
}
tmp[In] = dish;
dishs = tmp;
}
Dish searthDish(String dishName){
if(dishs==null)
return null;
for(int i=0;i<dishs.length;i++)
{
if(dishs[i].name.equals(dishName))
return dishs[i];
}
return null;
}
}
以上的是菜单类,用来记录菜系跟搜寻结束“end”,
主函数代码:

用一些String的方法跟实现成果的代码上来实现这个题的编写。学到了用一些String的方法实现一些功能的实现。
第二到题目的类图:

代码分析:

以上是菜肴类,可以在主函数里面中把其每道菜的价格给写出来。
public static void main(String[] args)
{
int flag=0;//判断是否开始订单
int i=0,num=0;
Scanner input = new Scanner(System.in);
String s;
Menu menu=new Menu();
Order order=new Order();
s=input.nextLine();
while(!s.equals("end"))
{
String[] b=s.split(" ");//分割
if(b[0].equals("1"))
flag=1;
if(flag==0)
{
menu.dishs[i]=new Dish();
if(menu.searthDish(b[0],i)==null)
{
menu.dishs[i]=menu.addDish(b[0],Integer.parseInt(b[1]));
i++;
}
else
menu.searthDish(b[0],i).unit_price=Integer.parseInt(b[1]);
}
else
{
if(menu.searthDish(b[1],i)!=null)
{
num=Integer.parseInt(b[0]);
order.records[num]=new Record();
order.records[num]=order.addARecord(num,menu.searthDish(b[1],i),Integer.parseInt(b[2]),Integer.parseInt(b[3]));
System.out.println(order.records[num].orderNum+" "+order.records[num].d.name+" "+order.records[Integer.parseInt(b[0])].getPrice());
}
else if(b[1].equals("delete"))
{
if(Integer.parseInt(b[0])<=num&&Integer.parseInt(b[0])>=1&&order.records[Integer.parseInt(b[0])].flag==0)
order.delete(Integer.parseInt(b[0]));
else
System.out.println("delete error;");
}
else
{
num=Integer.parseInt(b[0]);
order.records[num]=new Record();
Dish dish=new Dish();
dish.name=dish.name+b[1];
dish.unit_price=0;
order.records[num]=order.addARecord(num,dish,Integer.parseInt(b[2]),Integer.parseInt(b[3]));
System.out.println(b[1]+" does not exist");
}
}
s=input.nextLine();
}
System.out.println(order.getTotalPrice(num));
}
}
主要的代码用到了这些菜单、订单、菜品、记录等类。其中,菜单类包含菜品数组和查找菜品信息的方法,订单类包含记录数组和计算总价、添加记录、删除记录等方法,菜品类包含菜品名称、单价和计算价格的方法,记录类包含序号、菜品、份额、数量和计价的方法。在主函数中,通过输入不同的指令(1表示开始点餐,其他表示菜品信息或订单信息),根据不同的情况调用不同的方法,来实现点餐、查看订单、修改订单等功能。
class Menu
{
Dish[] dishs=new Dish[15];
Dish searthDish(String dishName,int k)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
{
for(int i=0;i<k;i++)
{
if(dishName.equals(dishs[i].name))
return dishs[i];
}
return null;
}
Dish addDish(String dishName,int unit_price)//添加一道菜品信息
{
Dish d=new Dish();
d.name=dishName.substring(0);
d.unit_price=unit_price;
return d;
}
}
菜单类主要跟第一道题的一样都是一道一道、菜补到菜单里面。
class Record
{
int orderNum;//序号\
Dish d;//菜品\
int portion;//份额(1/2/3代表小/中/大份)\
int flag=0;//是否被删除
int num;
int getPrice()//计价,计算本条记录的价格\
{
return (int)Math.round(d.getPrice(portion)*num);
}
}
以上是一个订单类其中包含了订单号 orderNum、菜品信息 d、份额 portion、删除标志 flag、数量 num 和计价方法 getPrice()。其中,菜品信息 d 是一个 Dish 类型的变量,表示这条记录所点的菜品。份额 portion 是一个整数,代表小/中/大份。计价方法 getPrice() 通过调用菜品信息 d 的 getPrice() 方法计算出本条记录的价格,并乘以数量 num。最后使用 Math.round() 方法将结果四舍五入为整数。
第三道点菜题目类图:

代码分析:
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Menu menu=new Menu();
Dish d;
String a ;//接受内容
a = in.next();
//创建菜单
while(!a.equals("end")) {
if(a.charAt(0)!='t'){
int price;
price=in.nextInt();
d=new Dish(a,price);
menu.add(d);
}
else
break;
a=in.next();
}
//订单,此时的a="table"
ArrayList<Order> orders = new ArrayList<Order>();
while(!a.equals("end")) {
int table=in.nextInt(); //接收第几桌
//接受订单信息
Order order = new Order(menu,table);
orders.add(order);
a=in.next(); //接收日期
String b = in.next(); //接收时间
order.account(a,b);
System.out.println("table "+table+": ");
while(true){
a=in.next();
if(a.equals("end")||a.equals("table"))
break;
String m=in.nextLine();
String[] p = m.split(" ");
if(p.length==4) {
//给本桌点餐
int orderNum = Integer.parseInt(a);
String dishName = p[1];
int portion = Integer.parseInt(p[2]);
int num = Integer.parseInt(p[3]);
//查找是否有此菜名
d = menu.searthDish(dishName);//接受菜品
if(d==null)//未找到,说明没有该菜品
System.out.println(dishName+" does not exist");
else {//找到了,添加订单
Record r = order.addARecord(orderNum, dishName, portion, num);
System.out.println(orderNum+" "+dishName+" "+r.getPrice());
}
}
if(p.length==5) {
//为别桌点菜
int orderNum = Integer.parseInt(p[1]);
String dishName = p[2];
int portion = Integer.parseInt(p[3]);
int num = Integer.parseInt(p[4]);
//查找是否有此菜名
d = menu.searthDish(dishName);//接受菜品
if(d==null)//未找到,说明没有该菜品
System.out.println(dishName+" does not exist");
else {//找到了,添加订单
Record r = order.addARecord(orderNum, dishName, portion, num);
System.out.println(orderNum+" table "+table
+" pay for table "+a+" "+r.getPrice());
}
}
if(p.length==2) {//删除
int orderNum = Integer.parseInt(a);
String dishName = p[1];
if(dishName.equals("delete"))
order.delARecordByOrderNum(orderNum);//删除订单信息
}
}
}
for(int i=0;i<orders.size();i++) {
if(orders.get(i).acc==0)
System.out.println("table "+orders.get(i).table+" out of opening hours");
else
System.out.println("table "+orders.get(i).table+
": "+orders.get(i).getTotalPrice());
}
in.close();
}
}
在菜单部分,首先创建了一个空的菜单对象,然后通过循环来不断接收用户输入的菜品名称和价格,将其封装成Dish对象并添加到菜单中,直到输入“end”为止。
在订单部分,首先创建了一个空的订单列表,然后通过循环来不断接收用户输入的桌号和订单信息,将其封装成Order对象并添加到订单列表中,直到输入“end”为止。每个订单对象包含一个菜单对象,以便查询菜品信息和计算订单总价。
在订单信息输入部分,首先接收日期和时间,然后通过循环来不断接收用户输入的菜品信息,将其封装成Record对象并添加到订单中,直到输入“end”或“table”为止。其中,菜品信息可能是为本桌点餐或为别桌点餐,通过判断输入字符串的长度来区分。如果是为别桌点餐,还需要输出付款信息。
整个代码逻辑比较清晰。
class Order {
ArrayList<Record> records = new ArrayList<Record>();// 保存订单上每一道的记录
Menu menu;
int table;
float acc;
void account(String a,String b) {//a接收日期,b接收时间
//计算星期几w
String[] s = a.split("/");
if(s[1].length()==1)
s[1]="0"+s[1];
if(s[2].length()==1)
s[2]="0"+s[2];
a = s[0]+"-"+s[1]+"-"+s[2];
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal=Calendar.getInstance();
Date date=null;
try {
date = format.parse(a);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cal.setTime(date);
int w=cal.get(Calendar.DAY_OF_WEEK)-1;
if(w<=0)
w=7;
//处理时间
String[] time = b.split("/");
int h=Integer.parseInt(time[0]);
int m=Integer.parseInt(time[1]);
if(w>=1&&w<=5) {
if(h>=17&&(h<20||(h==20&&m<30)))
acc=0.8f;
else if((h>10||(h==10&&m>=30))&&(h<14||(h==14&&m<30)))
acc=0.6f;
}
else if((h>9||(h==9&&m>=30))&&(h<21||(h==21&&m<30)))
acc=1;
}
int getTotalPrice(){
// 计算订单的总价
int total=0;
if(records==null)
return 0;
for(int i=0;i<records.size();i++)
total+=records.get(i).getPrice();
return Math.round(acc*total);
}
public Order(Menu menu,int table){
this.menu = menu;
this.table = table;
}
//根据菜名点菜
Record addARecord(int orderNum,String dishName,int portion,int num) {
//不用判断菜品是否存在,main里会判断,在这里一定会存在
Record r = new Record(orderNum,menu.searthDish(dishName),portion,num);
records.add(r);
return r;
}
void delARecordByOrderNum(int orderNum){
//根据序号删除一条记录
for(int i=0;i<records.size();i++) {
if(records.get(i).orderNum==orderNum) {
records.remove(i);
return ;//删除成功
}
}
System.out.println("delete error;");//删除失败
}
}
以上跟上一个点菜不一样的地方就是加了桌号,然后上面的去加了这种,还能进行删除。

全部的类图以上的是。
踩坑心得:
- 首先看到点菜这个题目时,没有过多的考虑,写的类很少,好多主要的东西都写在了主函数里面去,但是等到后面的出现更多的点菜系列的题目时,发现需要那些类才能更加的连贯,所有我之后直接去把类增多了,然后主函数里面的更多的时引用类来实现一些东西。
之前的类:

之后的类:

- 在写菜单里面的搜索菜的方法时没有做到简洁性,所有后面重新搞直接用代码的size来找长度,来进行得到菜。

3.一开始写的时候对代码的注释没有很好的体现,导致之后自己都有些东西看不懂了,所有之后还对自己的代码进行了分成意思以及注释了一下,使代码更加的连贯性跟整洁。缺少对类的说明和注释,不易于理解和维护。
计算星期几的方法可以使用Java 8的新特性 LocalDate,使代码更简洁和可读性更高。时间处理可以使用Java 8的新特性 LocalTime,使代码更简洁和可读更高。计算总价的方法可以使用Java 8的新特性 Stream,使代码更简洁和可读性更高。addARecord方法中的参数应该使用Dish对象而不是菜名字符串,这样可以避免重复查找菜品。delARecordByOrderNum方法应该返回一个布尔值表示是否删除成功,而不是使用System.out.println输出信息。

主要困难以及改进建议:
- 抽象思维能力:JAVA编程题通常需要程序员具备较高的抽象思维能力,够将实际问题抽象为代码实现。这对于初学者来说是一项挑战。

- 算法和数据结构:JAVA编程题涉及到算法和数据结构的应用,如排序、查找、树、图等,需要程序员具备扎实的算法和数据结构基础。
Scanner in = new Scanner(System.in);
Menu menu=new Menu();
Dish d;
String a ;//接受内容
a = in.next();
//创建菜单
while(!a.equals("end")) {
if(a.charAt(0)!='t'){
int price;
price=in.nextInt();
d=new Dish(a,price);
menu.add(d);
}
else
break;
a=in.next();
}
//订单,此时的a="table"
ArrayList<Order> orders = new ArrayList<Order>();
while(!a.equals("end")) {
int table=in.nextInt(); //接收第几桌
//接受订单信息
Order order = new Order(menu,table);
orders.add(order);
a=in.next(); //接收日期
String b = in.next(); //接收时间
order.account(a,b);
System.out.println("table "+table+": ");
while(true){
a=in.next();
if(a.equals("end")||a.equals("table"))
break;
String m=in.nextLine();
String[] p = m.split(" ");
if(p.length==4) {
//给本桌点餐
int orderNum = Integer.parseInt(a);
String dishName = p[1];
int portion = Integer.parseInt(p[2]);
int num = Integer.parseInt(p[3]);
//查找是否有此菜名
d = menu.searthDish(dishName);//接受菜品
if(d==null)//未找到,说明没有该菜品
System.out.println(dishName+" does not exist");
else {//找到了,添加订单
Record r = order.addARecord(orderNum, dishName, portion, num);
System.out.println(orderNum+" "+dishName+" "+r.getPrice());
}
}
if(p.length==5) {
//为别桌点菜
int orderNum = Integer.parseInt(p[1]);
String dishName = p[2];
int portion = Integer.parseInt(p[3]);
int num = Integer.parseInt(p[4]);
//查找是否有此菜名
d = menu.searthDish(dishName);//接受菜品
if(d==null)//未找到,说明没有该菜品
System.out.println(dishName+" does not exist");
else {//找到了,添加订单
Record r = order.addARecord(orderNum, dishName, portion, num);
System.out.println(orderNum+" table "+table
+" pay for table "+a+" "+r.getPrice());
}
}
if(p.length==2) {//删除
int orderNum = Integer.parseInt(a);
String dishName = p[1];
if(dishName.equals("delete"))
order.delARecordByOrderNum(orderNum);//删除订单信息
}
}
}
for(int i=0;i<orders.size();i++) {
if(orders.get(i).acc==0)
System.out.println("table "+orders.get(i).table+" out of opening hours");
else
System.out.println("table "+orders.get(i).table+
": "+orders.get(i).getTotalPrice());
}
in.close();
}
}
这些东西还是缺少一些灵活的策略。
前端传递参数时使用encodeURIComponent方法进行重新编码,后端因为spring默认会进行一次解码操作,所以可以直接获取。
改进:
代码的难度可以适量的降低一点点,更多来一点较为考验JAVA实际的特点的题目。
这个要先从多重继承概念说起
c++首先引入的多重继承带来了诸如菱形继承一类的问题,而后为了解决这个问题又不得不引入了虚继承这种概念。然而在实际的应用中人们发现继承更多的只被用在两种场合:扩充/改善基类,以及实现多态。对于前者,单继承足以;而对于后者,则真正需要的其实是纯抽象类,即只包含纯虚函数的基类。而对于这一种基类,由于其目的和普通的实例类已经有所不同,因此在java中将其改称为interface,即接口加以明确区分。
因此,java或者c#所谓的不支持多重继承,只是不支持对实例类的多重继承——因为这种继承所带来的一点点代码上的缩减远比不上其引入的麻烦,但是对于用于实现多态的多重继承,即implement interface依然是很好的支持了的。
面向对象的语言叫方法
面向过程的语言叫函数在java中没有函数这么一说,只有方法一说。实际上方法就是函数,函数就是方法,只是在不同的语言不同的称呼而已。
总结:
- 首先,我们学到了数组的定义和使用:点菜时需要记录菜品和数量,可以使用数组来存储这些信息。
- 循环结构的应用:在点菜时需要重复执行一定的操作,比如输入菜品和数量,可以使用循环结构来简化代码。
- 方法的定义和调用:可以将点菜的过程封装成一个方法,方便重复调用。
- 字符串的操作:在点菜时需要处理字符串,比如输入的菜品名称,可以使用字符串的方法来获取长度、比较、截取等操作。
- 异常处理:在输入菜品数量时,可能会出现非法输入,比如输入的不是数字,需要进行异常处理。
- 然后学到了类、继承、多态与抽象接口等。
- 在进行习题结构的考虑上需要自己再去调整与实践,用更多的编程题目去提高自己的能力。
- 老师讲课很好,无需更改。