Decorator pattern is used to add/modify existing class's behavior without changing class itself. So that acts as a wrapper for existing class, and may be therefore you thought of it. Point is your don't have system that you're extending, you are building it from scratch!
S/w design is tough and cannot be finalized in one go. Also I'm sure your prospect employer is more interested in how you design it, than what tech stack you use. So I'll not comment on that. It's your call.
Per your requirements, these are my initial thoughts. There is room for improvement (Yes!) but at the least this should work for the scope of your assignment. This is C#. That shouldn't stop you from understanding it though.
namespace Entities {
public class StoreItem
{
// Code
// Name
// Cost
// Tax -> for specific items
// MfgDate
// ExpDate
}
public class StoreDeal
{
// Code
// Name
// Cost
// Validity
// Items (type: IList<StoreItem>) -> items participating in a deal
}
}
namespace Domain {
public class Cart
{
// Items (type: IList<CartItem>)
// TotalAmount
// TotalDiscount
// FinalAmount
}
public class CartItem
{
public CartItem(string code) {
Code = code; // assume "6732" -> Chips
}
public CartItem(StoreItem item) {
MapStoreItem(item);
}
// declare props: Code, Name, Quantity, Cost
public void Prepare() {
if(Quantity > 0) {
// Invalid operation alert and return
// This is one time call per item type
}
// Sample. Retrieve item from database.
var item = new StoreItem { Code = code, Name = "Chips", Cost = 2.49, Tax = 0 /* etc */ }
MapStoreItem(item);
Quantity = 1;
}
public void UpdateQuantity(int quantity) {
Quantity = quantity;
Cost = Cost * Quantity;
}
private void MapStoreItem(StoreItem item) {
Code = item.Code;
Name = item.Name;
Cost = CalculateCost(item.Cost, item.Tax);
}
private static double CalculateCost(double cost, double tax) {
// If tax > 0, apply it to cost
// else return cost as is
}
}
}
public class DealService
{
public StoreDeal GetDeal(string itemCode) {
// Assume item to be Chips. Retrieve current deal that involve Chips.
// Sample data. You should delegate this stuff to data access layer.
return
new StoreDeal {
Code = "CS4.99",
Name = "Chips and salsa @ $4.99",
Cost = 4.99,
Items = new List<StoreItem> {
new StoreItem { Code = "6732", Name = "Chips" },
new StoreItem { Code = "4900", Name = "Salsa" }
}
}
}
}
public class CartService
{
private Cart cart;
private DealService dealService;
// ctor - inject dependencies
public CartService(Cart cart, DealService dealService) {
this.cart = cart;
this.dealService = dealService;
}
public void AddItem(CartItem item) {
var found = cart.Items.Find(i => i.Code == item.Code);
if (found != null) { // Update quantity
found.UpdateQuantity(found.Quantity + 1);
}
else { // Add new item
item.Prepare();
cart.Items.Add(item);
}
}
public void RemoveItem(string code) {
var found = cart.Items.Find(i => i.Code)
if (found != null) {
cart.Items.Remove(found);
}
}
public void CalculateTotal() {
// Used for checking which items in cart have got deal applied on.
// We don't want "CS4.99" deal applied to both Chips and Salsa, for ex. Only for one of them.
// So this collection simply holds deal codes already applied.
var dealsApplied = new List<string>();
foreach(var item in cart.Items) {
// Check deal
StoreDeal deal = dealService.GetDeal(item.Code);
// Apply the logic for TotalAmount, TotalDiscount, FinalAmount
}
}
}
Note that, if you were to design such system for real, then there would be much more classes than above. For example, in real case "Chips" is not an item, it's a type of item and hence cannot have Code. However, "Lays Potato Chips" would be an individual item of type "Chips" with it's own Code. Also StoreItem would become abstract entity which is derived by types like EdibleItem, PersonalCareItem, HealthCareItem, CosmeticItem and anything that exists in real store where EdibleItem will specifically have Nutrition info which does not apply to other in this list.
Lastly, I just wrote this (incomplete) code, didn't test it! Code is incomplete where you see comments, and did this purposely because I don't want you to cheat interview blindly. :)