Shopping Cart design interview task
I won't add to @mtj's comment (I totally agree that an array defined as a means to exchange information is a code smell).

I agree with @RobAu that you should stay far a away from those magic numbers and arrays. That would avoid bugs like:


this.counts[APPLE_INDEX] += other.getCounts()[ORANGE_INDEX];



Now to my comments.



Strategy is not the name of the Pattern applied here. It is more like a Composite Pattern, because several Strategies can be applied at the same time (although no method is available to add further discounts, but I suppose it was the intent).

In general I don't advise naming Objects by the Design Pattern they implement. Objects should be named as per what they do, not how you thought about making an architecture around them. It's useful in a tutorial, not in actual code. Carrying XXXStrategy everywhere gets real annoying, and lead to confusions (like a WallObserverListener : does it listen to an observer, or observe a listener?).

The solution to keep people to the page about you using a particular Pattern is Javadoc. This allows for cleaner code with method names that are more business-oriented, like:

public void apply(Discount discount);


Which is more obvious than:

public void addStrategy(CheckoutStrategy strategy);




A Better way to combine deals

You could use a Decorator pattern for your deals.

First clean up your interface:

public interface Checkout {
    double calculateTotal(List&lt;String&gt; shoppingCart);
}


Then make a simple price calculator (Note there is no hard-coded pricing, it can be created at runtime:

public class SimpleCheckout implements Checkout {

    private final Map&lt;String, Double&gt; basePrice = new HashMap&lt;&gt;();

    public void addPrice(String item, double price) {
        basePrice.put(item, price);
    }

    @Override
    public double calculateTotal(List&lt;String&gt; shoppingCart) {
        // Your own code, very good use of Streams, here
        return shoppingCart.stream().mapToDouble(basePrice::get).sum();
    }
}


Now we simply need to add discounts as a decoration layer:

public class DiscountValue implements Checkout {

    private final Checkout baseCheckout;
    private final String discountedItem;
    private final int minimumAmount;
    private final double discountValue;

    public DiscountValue(Checkout base, String item, int min, double discount) {
         this.baseCheckout = base;
         this.discountedItem = item;
         this.minimumAmount = min;
         this.discountValue = discount;
    }

    @Override
    public double calculateTotal(List&lt;String&gt; shoppingCart) {
        int count = Collections.frequency(shoppingCart, discountedItem);
        // Integer division gives the number of times the discount is applied
        double deduction = (count / minimumAmount) * discountValue;
        return baseCheckout.calculateTotal(shoppingCart) - deduction;
    }
}


Now this is how you use it:

public static void main(String[] argc){
    Checkout pricing = new SimpleCheckout();
    pricing.addPrice("Apple", 0.25);
    pricing.addPrice("Orange", 0.6);
    pricing = new DiscountValue(pricing, "Apple", 2, 0.25); // I'm using a straight-up refund here
    pricing = new DiscountValue(pricing, "Orange", 3, 0.60); // I'm using a straight-up refund here
    List&lt;String&gt; shoppingCart = new ArrayList&lt;&gt;();
    shoppingCart.add("Apple");
    shoppingCart.add("Orange");
    shoppingCart.add("Apple");
    shoppingCart.add("Apple");
    System.out.prinln(pricing.calculateTotal(shoppingCart));
}