Shopping cart with discounts I want to create a shopping cart project with discounts for products. For instance, if you buy 2 books, you can get 10% off Parker pens. I created a shopping cart example, but without exception handling in this version.

Are my classes Product, Basket, Offers and Discounts properly structured, or what changes do I need to make to make it right? To calculate discounts, should I iterate my basket or iterate the list of offers? The offers are a little tricky as mentioned at the top.

Product

public class Product {

    private String name;
    private int price;


...with get methods + hashcode and equals.

Basket

public class Basket {

    Map&lt;Product, Integer&gt; items;    

    public Basket() {
        items = new HashMap&lt;&gt;();
    }

    public Map&lt;Product, Integer&gt; getItems() {
        return items;
    }

    public void addProduct(Product product){
        if(items.containsKey(product)){
            items.compute(product, (p,q ) -&gt; Integer.valueOf(q+1));
        }else{
            items.put(product, 1);
        }
    }

    public void removeProduct(Product product){
        if(items.get(product).intValue() &gt; 1){
            items.compute(product, (p, q) -&gt; Integer.valueOf(q-1));
        }else{
            items.remove(product);
        }
    }
}


Discount

public class Discount {

    private Product product;    
    private int discountPercent ;

    public Product getProduct() {
        return product;
    }

    public int getDiscountPercent() {
        return discountPercent;
    }

    public Discount(Product product, int discountPercent) {
        super();
        this.product = product;     
        this.discountPercent = discountPercent;
    }

    @Override
    public String toString() {
        return "Discount [product=" + product + ", discountPercent=" + discountPercent + "]";
    }
}


Offer

public class Offer {

    private Product product;
    private int quantity;   
    private Discount discount;

    public Product getProduct() {
        return product;
    }
    public void setProduct(Product product) {
        this.product = product;
    }   

    public int getQuantity() {
        return quantity;
    }
    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
    public Discount getDiscount() {
        return discount;
    }
    public void setDiscount(Discount discount) {
        this.discount = discount;
    }

    public Offer(Product product, int quantity, Discount discount) {
        super();
        this.product = product;
        this.quantity = quantity;
        this.discount = discount;
    }
    @Override
    public String toString() {
        return "Offer [product=" + product + ", quantity=" + quantity + ", discount=" + discount + "]";
    }

}
You should have a class PriceComputer that computes prices and their discounts. This should be the central class of the whole design.

Then, make separate data types for the input and output of that class. That way the compiler prevents you from mixing these during the calculations (which will get quite complicated once you add more rules).

The input just needs to be the basket that you already have. You should change the HashMap to a LinkedHashMap, to keep the products in the same order they were inserted.

Each output element should have the properties product, quantity, resultingPrice, discount, discountPercent (only if applicable). All its fields should be final, since once computed, there is no reason to change them.

The general structure of your classes looks good. You might have a look at Project Lombok (which will save you from writing boring code), and you should make clear what the class Offer stands for, since it wasn't clear to me from the name alone.

Also, given an Offer, there are two ways of reaching a Product (offer.product and offer.discount.product). Are these products always the same? If so, one of them must be removed from the code.

Product.equals should not depend on the name of the product. Instead, only the SKU should be compared. Or, even simpler, make sure that you only have a single Product object per product, and don't override hashCode/equals at all.