我正在做一个练习,设计一个超市,为产品提供各种折扣。折扣的例子有:
- 购买x数量的物品可免费获得y
- 以$y购买y数量的物品
- 用$z购买物品x和物品y
我已经设法创建了前两个折扣。但由于折扣是根据 * 购物篮项目 * 计算的,我很难看到我如何才能使折扣适用于多个产品。我可以创建一个全新的项目,并标记为“x和y”,但这感觉有点像作弊。请提供建议
import java.math.BigDecimal;
public class Item {
private final String sku;
private final BigDecimal unitPrice;
public Item(String sku, BigDecimal unitPrice) {
this.sku = sku;
this.unitPrice = unitPrice;
}
public BigDecimal getUnitPrice() {
return unitPrice;
}
}
import java.math.BigDecimal;
public class BasketItem {
private final Item item;
private int quantity;
private final Discount discount;
public BasketItem(Item item, Discount discount) {
this.item = item;
this.discount = discount;
this.quantity = 1;
}
public BasketItem(Item item, Discount discount, int quantity) {
this.item = item;
this.discount = discount;
this.quantity = quantity;
}
public void increment() {
this.quantity++;
}
public BigDecimal calculateSubTotal() {
return item.getUnitPrice().multiply(new BigDecimal(quantity));
}
public BigDecimal calculateDiscount() {
return discount.apply(this);
}
public Item getItem() {
return item;
}
public int getQuantity() {
return quantity;
}
}
import java.math.BigDecimal;
public interface Discount {
BigDecimal apply(BasketItem item);
}
import java.math.BigDecimal;
import java.security.InvalidParameterException;
public class BuyXGetYFree implements Discount {
private final int buy;
private final int free;
public BuyXGetYFree(int buy, int free) {
if (buy < 1) {
throw new InvalidParameterException("Can't buy less than 1 item");
}
if (free < 1) {
throw new InvalidParameterException("Can't free less than 1 item for free");
}
if (free > buy) {
throw new InvalidParameterException("The free amount must not exceed the purchased amount");
}
this.buy = buy;
this.free = free;
}
@Override
public BigDecimal apply(BasketItem basketItem) {
int quantity = basketItem.getQuantity();
BigDecimal unitPrice = basketItem.getItem().getUnitPrice();
if (buy + free > quantity && quantity > buy) {
return unitPrice.multiply(BigDecimal.valueOf(quantity - buy));
}
int multiplier = quantity / (buy + free);
int forFree = multiplier * free;
return unitPrice.multiply(BigDecimal.valueOf(forFree));
}
}
import java.math.BigDecimal;
public class NoDiscount implements Discount {
@Override
public BigDecimal apply(BasketItem item) {
return BigDecimal.ZERO;
}
}
import java.math.BigDecimal;
import java.security.InvalidParameterException;
public class BuyXForY implements Discount{
int buy;
BigDecimal pay;
public BuyXForY(int buy, BigDecimal pay) {
if (buy < 1) {
throw new InvalidParameterException("Buy must be at least 1");
}
this.buy = buy;
this.pay = pay;
}
@Override
public BigDecimal apply(BasketItem item) {
int quantity = item.getQuantity();
if (quantity < buy) {
return BigDecimal.ZERO;
}
int multiplier = quantity / buy;
int remainder = quantity % buy;
BigDecimal buyAtDiscountedPrice = new BigDecimal(multiplier).multiply(pay);
BigDecimal buyAtNormalPrice = new BigDecimal(multiplier).multiply(new BigDecimal(remainder));
BigDecimal normalPrice = new BigDecimal(quantity).multiply(item.getItem().getUnitPrice());
return normalPrice.subtract(buyAtDiscountedPrice.add(buyAtNormalPrice));
}
}
public class DiscountAssignment {
private final Discount discount;
private final Item item;
public DiscountAssignment(Discount discount, Item item) {
this.discount = discount;
this.item = item;
}
public Discount getDiscount() {
return discount;
}
public Item getItem() {
return item;
}
}
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class Checkout {
private final List<BasketItem> basketItems;
private final List<DiscountAssignment> discountAssignments;
public Checkout(List<DiscountAssignment> discountAssignments) {
this.basketItems = new ArrayList<>();
this.discountAssignments = discountAssignments;
}
public void scan(Item item) {
Optional<BasketItem> basketItemOptional = basketItems.stream().filter(basketItem -> basketItem.getItem().equals(item)).findFirst();
if (basketItemOptional.isPresent()) {
basketItemOptional.get().increment();
return;
}
Optional<DiscountAssignment> discountsToApply = discountAssignments.stream().filter(discountAssignment -> discountAssignment.getItem().equals(item)).findFirst();
if (discountsToApply.isPresent()) {
basketItems.add(new BasketItem(item, discountsToApply.get().getDiscount()));
} else {
basketItems.add(new BasketItem(item, new NoDiscount()));
}
}
public BigDecimal total() {
System.out.println(basketItems);
return basketItems.stream()
.map(BasketItem::calculateSubTotal)
.reduce(BigDecimal.ZERO, BigDecimal::add)
.subtract(basketItems.stream()
.map(BasketItem::calculateDiscount)
.reduce(BigDecimal.ZERO, BigDecimal::add));
}
}
快速测试输出的总成本为4
import java.math.BigDecimal;
import java.util.List;
public class Test {
public static void main(String[] args) {
Item drink = new Item("Drink", new BigDecimal(1));
Item candy = new Item("Candy", new BigDecimal(1));
DiscountAssignment buyOneGetOneFreeDiscount = new DiscountAssignment(new BuyXGetYFree(1, 1), drink);
DiscountAssignment buyTwoForOneDollar = new DiscountAssignment(new BuyXForY(2, BigDecimal.ONE), candy);
Checkout checkout = new Checkout(List.of(buyOneGetOneFreeDiscount, buyTwoForOneDollar));
checkout.scan(drink);
checkout.scan(drink);
checkout.scan(drink);
checkout.scan(drink);
checkout.scan(candy);
checkout.scan(candy);
System.out.println("Total cost: " + checkout.total());
}
}
我尝试创建一个全新的捆绑项目。但每个项目必须单独扫描。
1条答案
按热度按时间jmo0nnb31#
我建议你尝试以下方法,而不是那些特殊的项目:
最后,收据可能会如下所示(每一行都是一个项目):
这样做的好处是可以显示原始价格以及添加的折扣。当然,如果需要,元素的顺序可以不同,但我基本上会保持这样: