Open/Closed Principle with calculating the total cost of items in a shopping cart
Basics


String comparison shouldn't be done with ==, unless you can carefully ensure you're using String.intern() everywhere so that the reference comparison will always match appropriately (not to forget the documentation too).
Keep your fields private!
Should PaymentCalculator.calculatePrice(OrderItem) really return 0 if there are no matching rules? That's like saying I can get oranges for free for a payment calculator that only (accidentally?) handle apples...


Rule-based vs if statements

// Add new rules here to support new SKUs. But why is this better
// than adding if/else in the old design? Because even this class 
// changes as we add more requirements right?


You can think of it that the calculation logic is not baked into the payment calculator, and that the logic can be maintained separately. For example, a more complex IPriceRule implementation might be retrieving prices from a database, and the calculator does not need to deal with any database connections know-how.