Design patterns for the SuperMarket system

I am a software developer. I'm starting to think like a software developer II. I am tasked with a relatively simple use for a coding request, the following as part of an interview: Build a supermarket pricing system.

Rules and Requirements: Each item in Super Foods is identified by a unique four-digit code. Today's pricing schemes at Super Foods use the following pricing categories, but be careful: prices are constant and the sales force always creates new incentives and deals, such as buy one-get-one for free.

EG: Chips and salsa (items # 6732 and # 4900) cost $ 4.99 together, but they cost $ 2.49 and $ 3.49 respectively.

EG2: Buy two toothbrushes for $ 1.99 each, get one free.

EG3: A bottle of wine (item # 0923) costs $ 15.49 and is taxed an additional 9.25%

After reading the design samples, it looks like a natural place for some form of Decorator

Pattern for total object sales. A SQLite database with a schema <ID, ObjectName, Price>

will also be useful in some way, although I'm rusting on how we're going to make data access objects in all of this.

I'm trying to ponder this in the fullness of the MVC mindset, I feel like I might laugh at something. Is this what the Spring Framework is famous for? Maybe an even better API for this use case is recommended?

Thanks for helping me brainstorm the design of this system.

+3


source to share


4 answers


Decorator drawing is used to add / modify existing behavior of a class without changing the class itself. This way it acts as a wrapper for an existing class and so you might want to consider this. You don't have a system that you are expanding, you are building it from scratch!

The S / W design is rigid and cannot be completed in one go. Also I'm sure your potential employer is more interested in how you design it than the one you use. Therefore, I will not comment on this. This is your call.

As per your requirements, these are my initial thoughts. There is room for improvement (yes!), But at least this should work within your assignment. It with#. This shouldn't stop you from understanding it.



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 planning such a system for real then there would be a lot more classes than the above. For example, in the real case "Chips" is not an element, it is an element type and therefore cannot have a code. However, "Lays Potato Chips" will be a separate item of the "Chips" type with its own code. Also StoreItem will become an abstract entity that is inferred by types such as EdibleItem, PersonalCareItem, HealthCareItem, CosmeticItem and anything that exists in a real store where EdibleItem will specifically have nutritional information that is not related to others on this list.

Finally, I just wrote this (incomplete) code, haven't tested it! The code is incomplete where you see the comments, and I did it on purpose, because I don't want you to blindly cheat the interview. :)

+2


source


I took the liberty of adding a little more than design templates. I saw this as an exercise too :) Let's break it down and walk through my thought process:

  • Representing numbers and names in the system as types
  • ID

    - four digits - unsigned short int

    - we only need digits from 0 to 9999, which means we only need 14 bits (2 ^ 14 = 16384) and unsigned short int uses 16 bits. This gives us space if we would like to increase the number of elements to 65536 (2 ^ 16)
  • Name

    - string UTF-16

    usually good enough. However, we must remember that some products may come from distant countries and use different symbols. UTF-16 only has 16 bits per character (65536 again), so we have to remember in our implementation that if we need more bits we need to use a different encoding (e.g. UTF-32)
  • Price

    or Discount

    is it float

    good enough? I think not. In many languages, performing various arithmetic operations results in not completely correct answers (try it in JavaScript 0.2 * 0.4

    - you can use your browser console). When it comes to money, you don't want to increase prices or free money. There are special libraries and implementation types to be safe when it comes to money.
  1. Data structures and classes
  • Item

    - class / structure with the following fields: ID

    , Name

    , Original price

    (the types described above)
  • Item Collection

    - array . Since we are using short unsigned int

    for IDs, we can also use it to index an array... We can even initialize the entire array and load all items into memory when the app starts up.
  • PriceModifier

    - ID

    - short unsigned int

    , Type

    - ENUM to represent the type of discount (or tax) and know what to do in the case, it is applied, Name

    - String UTF-16 (just to inform the user), Value

    - the short signed int

    percentage modifier
  • PairPriceModifier

    - class

    - expands PriceModifier

    and adds a couple of elements IDs

    .
  • PriceModifier Collection

    - here we need to use a quick lookup structure as we use ID

    like short usigned int

    we can use an array of array... This list will not change often. When we need to add / remove a modifier, we can do it in linear time O (1) * O (m), where m is the length of the modifier a Item

    . We will not physically copy Modifiers as we can use object references PriceModifier

    .
  • Shopping Cart Collection

    - the key functionality of every store is the shopping cart, it needs to be optimized for: adding / removing items and the list of saved items. We need to add / remove items frequently and check for items already added to apply different discounts, but we also want a list of all saved items (eg in a cart). We can use a hash table with a related array[have O (1) when finding / adding / removing items and O (n) when listing] We update the Final Price when we add / remove an item. In an arraywe keep a reference to the class object that represents the item from the store to see which one PriceModifier

    was applied.
  • CartItem

    - class

    with fields: ItemID

    - short unsigned int

    , Quantity

    - unsigned int

    , AppliedPriceModifier Collection

    - hash table for easy access PriceModifiers

    with associated arrayto list them in the Trash view.
  • AppliedPriceModifier

    - class

    with the fields PriceModifierID

    ,Quantity

Interesting case: if we add some element to Shopping Cart Collection

, we need to check PriceModifier Collection

. In O (1), we can access the correct list PriceModifiers

that we need to apply. Then if we notice PairPriceModifier

we need to check Shopping Cart Collection

againm if we don't have a paired element. whole operation:

  • O (1) - to get an array of of PriceModifier

    length m
  • O (m) - go through an array and apply modifiers
  • O (1) - if we found PairPriceModifier

    , we are accessing an existing item fromShopping Cart Collection

  • O (k) + O (m) - update collections AppliedPriceModifier

    for both elements inShopping Cart Collection

  • O (1) - update final price (explained below)
  1. Design patterns


  • For the whole APP structure, I find it advisable to use some framework with Inversion of Control . To make our code modular and easier to unit test, we can use the dependecy injection template .
  • For the presentation layer, we can use either MVC or its mutation - MVVM. This will give us the ability to double-link to quickly update the UI. Information about the final price, transactions and applicable discounts or taxes is essential.
  • We can use the Observer template to update the final price . We observe and when something goes or goes out, we can update the final price at constant times Shopping Cart Collection

  • To keep our code compact, we can use chaining (Cascade)
  • You can use the Decorator pattern to add additional functionality without changing the classes (for installations where one of the situations prevents the other from being applied ) PriceModifiers

    PriceModifier

  • To keep CartItems Collection

    safe from changes outside the cart, we can use the Mediator design pattern . This broker service will PriceModifiers

    only be responsible for the application when added or removed Item

    fromCart Collection

  1. Other questions

We can expand the topic and ask:

  • How to submit your data to DB
  • What if we want to increase the number of elements and represent them as 10.000 letters with the letter α
  • What if we want to keep our shopping app 99.9% stable and running.
  • How can we handle multiple requests
  • What happens if a customer has a discount in their cart, but the system administrator removes that discount from the system, and many more.

Please add some comments as this is an interesting topic for me. What can I improve / change? What have I not thought?

+1


source


possible steps:

  • define the database model
  • mirror db model in java
  • implement DAO layer -> CRUD operations
  • implement service level -> business logic
  • display service level → eg. REST
  • implement a client side that is a client for an open service level.
0


source


Ok, this is the answer to a logical perspective without any design patterns. The table you have with the item code and price is lovely. Therefore, if there are no deals and incentives for any of the items on the list that is being billed, simply use this table, calculate the total cost, and complete the check. Now that there are suggestions / incentives for any product (s) on the checkout list, you will have to go through various combinations.

To simplify the problem statement: suppose there are 3 items in the list.

So, you will have to look at the following combinations: Item 1, item 2, item3 Item 1, item2 Item1, Item3 Item2 Item3

Now, for any of these combinations, you will need to search for a list of deals / incentives. It looks like I'm googling for the line "Item1 Item2" and I end up with a set of web links that are deals / incentives for this combination.

Inside the combination, I will check which one is active right now and apply the trade price on it.

After setting the trade price, remove the combination of items from the checklist and continue searching for the remaining items in the list.

Hope this helps.

0


source







All Articles