Golang : The OOP Pattern.
Tags: programming, go, beginners
Published: 2023-01-10 07:14:43

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:

```go
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
}
```

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:
```go
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
}

```

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.

```go
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
}
```

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.