//菜单
import java.text.DecimalFormat; import java.util.Scanner; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { // 主程序入口 Menu menu = new Menu(); // 创建菜谱对象 menu.addDish("西红柿炒蛋", 15); // 添加菜品信息 menu.addDish("清炒土豆丝", 12); menu.addDish("麻婆豆腐", 12); menu.addDish("油淋生菜", 9); Order order = new Order(); // 创建订单对象 Scanner in = new Scanner(System.in); // 进入订单录入循环 while (true) { System.out.println("请输入订单信息(序号 菜名 份额 数量),输入0结束订单录入:"); int orderNum = in.nextInt(); if (orderNum == 0) { break; } String dishName = in.next(); int portion = in.nextInt(); int num = in.nextInt(); order.addARecord(orderNum, dishName, portion, num, menu); // 添加一条订单记录 } // 计算并输出订单总价 int totalPrice = order.getTotalPrice(); DecimalFormat df = new DecimalFormat("#.00"); System.out.println("订单总价:" + df.format(totalPrice)); } } public class Dish { private String name; // 菜品名称 private int unit_price; // 单价 public Dish(String name, int unit_price) { this.name = name; this.unit_price = unit_price; } public String getName() { return name; } public int getUnit_price() { return unit_price; } public int getPrice(int portion) { // 计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) double price; switch (portion) { case 1: price = unit_price; break; case 2: price = unit_price * 1.5; break; case 3: price = unit_price * 2; break; default: throw new IllegalArgumentException("Invalid portion value. Portion must be 1, 2, or 3."); } return (int) Math.round(price); } } public class Menu { private Map<String, Dish> dishes; // 菜品信息,以菜名为键,Dish对象为值 public Menu() { dishes = new HashMap<>(); } public void addDish(String dishName, int unit_price) { // 添加一道菜品信息 Dish dish = new Dish(dishName, unit_price); dishes.put(dishName, dish); } public Dish searchDish(String dishName) { // 根据菜名在菜谱中查找菜品信息,返回Dish对象 return dishes.getOrDefault(dishName, null); } } public class Order { private Map<Integer, Record> records; // 订单上的记录,以序号为键,Record对象为值 public Order() { records = new HashMap<>(); } public void addARecord(int orderNum, String dishName, int portion, int num, Menu menu) { // 添加一条菜品信息到订单中 Dish dish = menu.searchDish(dishName); if (dish == null) { throw new IllegalArgumentException("Dish not found in the menu."); } Record record = new Record(orderNum, dish, portion); records.put(orderNum, record); } public void delARecordByOrderNum(int orderNum) { // 根据序号删除一条记录 records.remove(orderNum); } public Record findRecordByNum(int orderNum) { // 根据序号查找订单记录,返回Record对象 return records.getOrDefault(orderNum, null); } public int getTotalPrice() { // 计算订单的总价 int totalPrice = 0; for (Record record : records.values()) { totalPrice += record.getPrice(); } return totalPrice; } } public class Record { private int orderNum; // 序号 private Dish dish; // 菜品 private int portion; // 份额(1/2/3代表小/中/大份) public Record(int orderNum, Dish dish, int portion) { this.orderNum = orderNum; this.dish = dish; this.portion = portion; } public int getOrderNum() { return orderNum; } public Dish getDish() { return dish; } public int getPortion() { return portion; } public int getPrice() { // 计价,计算本条记录的价格 return dish.getPrice(portion); } }
(1)首先,我们需要定义几个类来表示不同的对象:菜品类(Dish)、菜谱类(Menu)、点菜记录类(Record)、订单类(Order)。
-
菜品类(Dish):
- 属性:菜品名称(name)、基础价格(unit_price)。
- 方法:getPrice(int portion):根据不同份额计算菜品价格。
-
菜谱类(Menu):
- 属性:菜品数组(dishs),保存所有菜品信息。
- 方法:searthDish(String dishName):根据菜名在菜谱中查找菜品信息并返回Dish对象。 addDish(String dishName, int unit_price):添加一道菜品信息到菜谱。
-
点菜记录类(Record):
- 属性:序号(orderNum)、菜品(Dish对象)、份额(portion)。
- 方法:getPrice():计算本条记录的价格。
-
订单类(Order):
- 属性:记录数组(records),保存订单上的每一道菜的记录。
- 方法:getTotalPrice():计算订单的总价。 addARecord(int orderNum, String dishName, int portion, int num):添加一条菜品信息到订单中。 delARecordByOrderNum(int orderNum):根据序号删除一条记录。 findRecordByNum(int orderNum):根据序号查找一条记录。
(2)接下来,我们需要解析输入的内容并进行处理:
- 读取输入,解析菜单信息和订单信息。
- 根据解析的菜单信息创建菜谱对象,并将菜品信息存储到菜谱中。
- 遍历订单信息,根据桌号标识的格式判断是否为有效的桌号信息。
- 如果是有效的桌号信息,根据桌号创建订单对象,并处理点菜记录和删除记录。
- 如果不是有效的桌号信息,忽略当前信息,继续处理下一条记录。
- 对每个订单对象,计算总价并按要求输出订单的处理信息。
- 按输入顺序输出每一桌的总价。
在处理过程中,需要注意处理异常情况并进行相应的输出,例如非法格式、重复删除、菜谱信息与订单信息混合等。
(3)我在实现过程中遇到了一些坑:
- 在处理代点菜信息时,需要判断被点菜桌号是否存在,否则输出相应的错误信息。
- 当记录的序号不按顺序排列时,需要进行排序并输出相应的错误信息。
- 对于菜谱信息中的重复菜品名,应该以最后一条记录为准。
//期中考试题4
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); ArrayList<Shape> list = new ArrayList<>(); int choice = input.nextInt(); while (choice != 0) { switch (choice) { case 1: // Circle double radius = input.nextDouble(); Shape circle = new Circle(radius); list.add(circle); break; case 2: // Rectangle double x1 = input.nextDouble(); double y1 = input.nextDouble(); double x2 = input.nextDouble(); double y2 = input.nextDouble(); Point leftTopPoint = new Point(x1, y1); Point lowerRightPoint = new Point(x2, y2); Rectangle rectangle = new Rectangle(leftTopPoint, lowerRightPoint); list.add(rectangle); break; } choice = input.nextInt(); } Collections.sort(list); for (int i = 0; i < list.size(); i++) { System.out.print(String.format("%.2f", list.get(i).getArea()) + " "); } } } class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } @Override public double getArea() { return Math.PI * radius * radius; } } class Point { Point(double x, double y) { this.x = x; this.y = y; } public double getX() { return x; } public void setX(double x) { this.x = x; } public double getY() { return y; } public void setY(double y) { this.y = y; } double x, y; } class Rectangle extends Shape { private Point leftTopPoint; private Point lowerRightPoint; public Rectangle(Point leftTopPoint, Point lowerRightPoint) { this.leftTopPoint = leftTopPoint; this.lowerRightPoint = lowerRightPoint; } public Point getLeftTopPoint() { return leftTopPoint; } public Point getLowerRightPoint() { return lowerRightPoint; } @Override public double getArea() { double width = lowerRightPoint.getX() - leftTopPoint.getX(); double height = lowerRightPoint.getY() - leftTopPoint.getY(); return width * height; } } //定义一个Shape类,表示图形,实现Comparable接口 class Shape implements Comparable<Shape> { public Shape() { } public double getArea() { return 0; } public int compareTo(Shape shape) { double s1, s2; s1 = getArea(); s2 = shape.getArea(); if (s1 > s2) return 1; else if (s1 < s2) return -1; return 0; } }本题要求重构类设计,实现列表内图形的排序功能,按照图形的面积进行排序。题目中提到要实现Comparable接口。
以下是对这道题目的分析:
(1)前言: 该题目是在测验3的基础上进行重构,要求实现图形列表的排序功能。题目给出了一个Main类,其中使用了ArrayList存储图形对象,并通过输入不同的图形类型和参数来创建图形对象并添加到列表中。最后要求按照图形的面积进行排序,并输出排序后的图形面积。
-
-
(2)设计与分析: 题目给出的Main类中,通过Scanner从用户输入获取图形类型和参数,根据不同的类型创建相应的图形对象,然后将图形对象添加到ArrayList中。最后通过调用
list.sort(Comparator.naturalOrder())
实现对列表中图形的排序,排序依据是图形的面积。为了实现图形的排序功能,需要在Shape类中实现Comparable接口,并重写
compareTo()
方法。首先需要在Shape类的声明中添加implements Comparable<Shape>
来表示Shape类实现了Comparable接口。然后在Shape类中实现compareTo()
方法,该方法用于比较两个图形对象的面积大小,并返回比较结果。比较时,可以通过调用getArea()
方法获取图形的面积,并使用Double.compare()方法进行比较。
-
-
(3)踩坑心得: 在实现该题目时,可能会遇到以下几个容易出错的地方:
-
忘记实现Comparable接口:要实现图形对象的排序功能,必须在Shape类中实现Comparable接口,并重写compareTo()方法。如果忘记添加implements Comparable<Shape>,或者忘记实现compareTo()方法,将无法进行排序操作。
-
比较方法的实现:在compareTo()方法中,需要比较两个图形对象的面积大小,并返回比较结果。使用Double.compare()方法可以方便地进行浮点数的比较。确保在比较前调用getArea()方法获取图形的面积。
-
输入错误导致排序错误:在用户输入图形类型和参数时,需要确保输入的数据符合要求。如果输入错误的类型或参数,可能会导致创建的图形对象不正确,进而影响排序结果。确保输入正确的图形类型和对应的参数,以保证排序功能的正确实现。
(4)改进建议: 在这道题目中,对类设计进行了重构,实现了图形列表的排序功能。以下是一些建议改进的地方:
-
使用更具有可读性的变量名:在输入图形类型和参数时,建议使用更具有可读性的变量名,例如radius代表圆的半径,x1、y1、x2、y2代表矩形的两个点坐标等。这样可以提高代码的可读性和可维护性。
-
添加异常处理机制:在用户输入图形类型和参数时,可能会出现输入错误的情况,例如输入非法的类型或参数。建议添加异常处理机制,对输入进行合法性检查,并在出现异常时给予用户提示,以增强程序的健壮性。
-
扩展更多的图形类型:当前题目中只涉及圆形和矩形两种图形类型,可以考虑扩展更多的图形类型,例如三角形、正方形等。这样可以进一步丰富题目的内容,提供更多的练习机会。
(5)总结: 通过完成该题目,我们学习了如何重构类设计以实现特定功能,以及如何利用Comparable接口实现对象的排序功能。同时,我们还加深了对继承、多态和接口的理解。
在今后的学习中,我们可以继续扩展和深入了解类设计的相关知识,探索更多的排序算法和数据结构。此外,我们还可以学习其他面向对象编程语言中的类设计和接口概念,以提升对软件设计的理解和能力。
-