You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java OOP:如何向ArrayList添加商品、实现临期折扣及收银小票打印

Java超市购物系统功能实现方案

1. Food实例添加到Cart集合实现

首先修复原有Cart类的问题:

  • 移除products属性不必要的static修饰(除非需要全局唯一购物车)
  • 初始化products为ArrayList实例
  • 优化add方法支持单个/批量添加商品,补充移除商品方法
  • 因为Food继承自BaseProduct,基于多态特性可以直接存入List<BaseProduct>集合

修改后的Cart类代码:

package Cart;

import Products.BaseProduct;
import Products.PerishableProducts.Food;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Cart {
    // 初始化商品集合
    private List<BaseProduct> products = new ArrayList<>();

    // 添加单个商品
    public void add(BaseProduct product) {
        // 前置校验:过期商品不能加入购物车
        if (product instanceof Food) {
            Food food = (Food) product;
            if (new Date().after(food.getExpirationDate())) {
                throw new RuntimeException("商品已过期,无法加入购物车");
            }
        }
        products.add(product);
    }

    // 批量添加商品
    public void addBatch(List<BaseProduct> productList) {
        productList.forEach(this::add);
    }

    // 移除单个商品
    public boolean remove(BaseProduct product) {
        return products.remove(product);
    }

    // 获取所有商品
    public List<BaseProduct> getProducts() {
        return new ArrayList<>(products);
    }

    // 清空购物车
    public void clear() {
        products.clear();
    }
}

2. 临期折扣逻辑实现

核心逻辑:计算购买日期和商品过期日期的间隔天数,间隔<5天则享受9折优惠,折扣金额为原价的10%。
推荐实现方案:

  1. 给抽象类BaseProduct新增抽象计算实付价格、折扣金额的方法,适配后续多品类折扣扩展
  2. Food类实现该方法,加入临期折扣判断逻辑
  3. 日期计算转成LocalDate处理,避免Date类的时区、时间戳计算误差问题

首先在BaseProduct抽象类新增抽象方法:

public abstract Double getActualPrice(Date buyDate);
public abstract Double getDiscountAmount(Date buyDate);

Food类实现对应方法:

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;

// 实现抽象方法:获取实付价格
@Override
public Double getActualPrice(Date buyDate) {
    return getPrice() * (1 - getDiscountRate(buyDate));
}

// 实现抽象方法:获取折扣金额
@Override
public Double getDiscountAmount(Date buyDate) {
    return getPrice() * getDiscountRate(buyDate);
}

// 私有方法计算折扣率
private double getDiscountRate(Date buyDate) {
    // 转成LocalDate计算天数差
    LocalDate buyLocalDate = buyDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    LocalDate expireLocalDate = expirationDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    // 计算间隔天数
    long daysBetween = ChronoUnit.DAYS.between(buyLocalDate, expireLocalDate);
    // 不足5天返回0.1的折扣率(即减10%),否则无折扣
    return daysBetween < 5 && daysBetween >= 0 ? 0.1 : 0d;
}

3. Cashier收银员类实现

小票打印逻辑步骤:

  1. 接收Cart实例和购买日期参数
  2. 对购物车商品按名称+品牌分组统计购买数量
  3. 遍历分组计算每个商品的小计金额、折扣金额
  4. 累加得到总消费金额、总折扣金额
  5. 格式化打印小票内容

Cashier类代码:

package Service;

import Cart.Cart;
import Products.BaseProduct;
import java.util.Date;
import java.util.Map;
import java.util.stream.Collectors;

public class Cashier {
    public void printReceipt(Cart cart, Date buyDate) {
        // 按商品名称+品牌分组统计数量
        Map<String, Long> countMap = cart.getProducts().stream()
                .collect(Collectors.groupingBy(p -> p.getName() + "-" + p.getBrand(), Collectors.counting()));
        // 按分组去重后的商品映射
        Map<String, BaseProduct> productMap = cart.getProducts().stream()
                .collect(Collectors.toMap(p -> p.getName() + "-" + p.getBrand(), p -> p, (p1, p2) -> p1));

        double totalAmount = 0d;
        double totalDiscount = 0d;

        // 打印小票头
        System.out.println("====================购物小票====================");
        System.out.printf("购买时间:%tF %tT%n", buyDate, buyDate);
        System.out.println("商品名称\t品牌\t单价\t数量\t小计\t折扣");
        System.out.println("-----------------------------------------------");

        // 遍历打印每个商品
        for (String key : countMap.keySet()) {
            BaseProduct product = productMap.get(key);
            long count = countMap.get(key);
            double subTotal = product.getActualPrice(buyDate) * count;
            double subDiscount = product.getDiscountAmount(buyDate) * count;

            System.out.printf("%s\t%s\t%.2f\t%d\t%.2f\t%.2f%n",
                    product.getName(), product.getBrand(), product.getPrice(),
                    count, subTotal, subDiscount);

            totalAmount += subTotal;
            totalDiscount += subDiscount;
        }

        // 打印合计
        System.out.println("-----------------------------------------------");
        System.out.printf("总消费金额:%.2f 元%n", totalAmount);
        System.out.printf("总折扣金额:%.2f 元%n", totalDiscount);
        System.out.println("===============================================");
    }
}

注意事项

  • 金额计算推荐用BigDecimal替代Double,避免浮点数精度丢失问题
  • 日期处理建议全量升级为Java8+的LocalDate/LocalDateTime,废弃旧的Date类
  • 可根据业务需求新增过期商品拦截、折扣叠加等扩展逻辑

内容的提问来源于stack exchange,提问作者georgik1_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 08:06:03