DEV Community

Jotham Ntekim
Jotham Ntekim

Posted on

Golang : The OOP Pattern.

Programming is a creative task: there is no right or wrong way to solve a problem, in the same way, that there is no right or wrong way to paint a picture.

In this article, I will walk you through how I did my AltSchool Project. We'll learn about some OOP Concepts - Encapsulation, Abstraction, Inheritance, and Polymorphism.

But before I get started, let me brief you on what the project is about...

John has just opened up his car selling shop, to sell different cars. He gets the cars he needs to sell from different people and they all bring it to him. He needs to manage the list of cars he has, attach a price to them, and put them on display to be sold, basically John needs an inventory to manage cars & to manage sales. For instance,

  1. He needs to see the number of cars that are left to be sold

  2. He needs to see the sum of the prices of the cars left

  3. He needs to see the number of cars he has sold

  4. Sum total of the prices of cars he has sold

  5. A list of orders that for the sales he made

Using the knowledge of OOP in Go, Build simple classes for the following “objects”

● Car
● Product
● Store

The Car class can have any car attributes you can think of.

The Product class should have attributes of a product i.e (theproduct, quantityofthe
productinstock,priceoftheproduct).

A car is a product of the store, but there can be other products so the attribute of the car can be promoted to the Product. The Product class should have methods to display a product, and a method to display the status of a product if it is still in stock or not.

The Store class should have attributes like

● Number of products in the store that are still up for sale
● Adding an Item to the store
● Listing all product items in the store
● Sell an item
● Show a list of sold items and the total price

So basically we'll be building a mini-ecommerce platform that will help John make sales and at the same time keep track of his sales.

Let me point out a few things, though Car is the main Product John deals on, he sells other Car accessories such as headlights, tyres etc so our Car class here will cover for all items John sells.

Defining the deliverables or functionalities of this app will be our first task. We’ll do this by creating a Store Interface. Interface basically helps us define a set of attributes or behaviors that a class implements. So instead of creating a function for each type of Product(Camry Car, Tyres, Car Headlights etc), whatever form the Product class takes, they'll be able to extend the interface functions. Attributes like "adding an item to the store" , "selling an item" will be common to any product whether an actual car or car accessories hence the need for interfaces. Interfaces is one way Go implements Polymorphism – one of the concept in Objected Oriented Programming.

Here is the Store definition:

type Store interface {
    AddProduct(prod models.Product) models.Product
    SellProduct(prod models.Product) models.Product
    ProductList() []models.Product
    OnSaleProducts() []models.Product
    SoldProductList() []models.Product
    OnSaleProductPriceTotal() float64
    SoldProductPriceTotal() float64
    DisplayStatus() string
}
Enter fullscreen mode Exit fullscreen mode

Next step is to create Car, and Product class. Go does not support the actual Class keyword as in other languages like JavaScript, so we'll be using struct to define each of this classes. Like Class/Object in JavaScript and Dictionary in python, Go’s structs are typed collections of fields. They’re useful for grouping data together to form records.

So in case of Car and Product collection, the class will be defined as below:

type Car struct {
    Id        string
    Name      string
    Model     string
    Price     float64
    IsCarType bool
    DateAdded string
    Color     string
}

type Product struct {
    Id         string
    Item       Car
    QtyInStock uint64
    TotalPrice float64
    OutOfStock bool
}

Enter fullscreen mode Exit fullscreen mode

While declaring the Car and Product class, I capitalized "C" and "P" as well as the first letter for each of the field in each collection to make it accessible aside that package/file. Instead of "public" and "private" keyword like in other language, use of uppercase and lowercase for the first letter of any keyword is Go's way of encapsulation. Also, if you note, I used the "Car" struct as the type for "Item" in the "Product" struct, that's one way of implementing Inheritance(The Product class inherited the attributes of the Car class).

Now let’s extend the methods we defined in the Store Interfaces, that way our program can know what each method is supposed to do.

var products []models.Product
var availableProducts = products
var soldProducts []models.Product

func (product Product) AddProduct(prod models.Product) models.Product {
    productExists := false
    index := 0
    for i, item := range availableProducts {
        if item.Item.Name == prod.Item.Name && item.Item.Model == prod.Item.Model {
            productExists = true
            index = i

            break
        }
    }
    if productExists {
        availableProducts[index].QtyInStock += 1
        availableProducts[index].TotalPrice += prod.Item.Price
    } else {
        prod.Id = strconv.Itoa(rand.Intn(1000000000))
        prod.TotalPrice = prod.Item.Price * float64(prod.QtyInStock)
        prod.OutOfStock = false
        products = append(products, prod)
        availableProducts = append(availableProducts, prod)
    }

    fmt.Println("Product added successfully!")

    return prod
}

func (product Product) SellProduct(prod models.Product) models.Product {

    //availableProducts := availProductList
    isEqual := false
    greaterThanOne := false
    index := 0
    for i, item := range availableProducts {
        if item.Item.Id == prod.Item.Id {
            isEqual = true
            index = i
            if item.QtyInStock > 1 {
                greaterThanOne = true
            }
            break
        }
    }
    if isEqual {
        if greaterThanOne {
            availableProducts[index].QtyInStock -= 1
            availableProducts[index].TotalPrice -= prod.Item.Price
            availableProducts[index].OutOfStock = false
            for _, item := range products {
                if item.Id == prod.Id {
                    item.QtyInStock -= 1
                    item.TotalPrice -= prod.Item.Price
                    item.OutOfStock = false

                    break
                }
            }
        } else {
            availableProducts = append(availableProducts[:index-1], availableProducts[index+1:]...)
            for _, item := range products {
                if item.Id == prod.Id {
                    item.OutOfStock = true
                    break
                }
            }
            productExists := false
            index := 0
            for i, item := range soldProducts {
                if item.Item.Name == prod.Item.Name && item.Item.Model == prod.Item.Model {
                    productExists = true
                    index = i

                    break
                }
            }
            if productExists {
                soldProducts[index].QtyInStock += 1
                soldProducts[index].TotalPrice += prod.Item.Price
            } else {
                prod.TotalPrice = prod.Item.Price * float64(prod.QtyInStock)
                soldProducts = append(soldProducts, prod)
            }

        }

    }
    fmt.Println("Sale successful!")

    return prod
}
func (product Product) OnSaleProductPriceTotal() float64 {
    var totalPrice float64
    for _, item := range availableProducts {
        totalPrice += item.TotalPrice
    }

    return totalPrice
}

func (product Product) DisplayStatus() string {
    var status string
    for _, item := range products {
        if item.OutOfStock == false {
            status = "Still on sale!"
        } else {
            status = "Out of stock!"
        }
    }
    return status
}

func (product Product) SoldProductPriceTotal() float64 {
    var totalPrice float64
    for _, item := range soldProducts {
        totalPrice += item.TotalPrice
    }

    return totalPrice
}

func (product Product) ProductList() []models.Product {

    return products
}

func (product Product) SoldProductList() []models.Product {

    return soldProducts
}

func (product Product) OnSaleProducts() []models.Product {

    return availableProducts
}
Enter fullscreen mode Exit fullscreen mode

So far we’ve been able to create a set of classes and functions that will help John record and track his sales. We learnt about basic types such as Struct and Interfaces as well as some OOP concepts in Go.
Hopefully, I’ll write another article on other Go types like maps, pointers as well as how Go implements concepts like Constructors, Abstraction etc. Meanwhile do well to drop any questions on the comment section.

Thank You.

Top comments (0)