Introduction
This week, we explored key Go concepts, such as slices, maps, structs, methods and interfaces. To reinforce our learning, we built a Geometry Tracker, a mini project that ties everything together. In this article, we’ll break down our approach, explain how each components works, and reflect on the lessons learned.
Key Concepts We Covered
Slices
- A dynamic array-like data structure in Go.
- Used to store multiple shapes in our project.
Maps
- A key-value store, allowing us to track shape areas.
- Used to store the total area of different shape types.
Struct
- A way to define complex data types.
- Used to define Circle and Rectangle with relevant attributes.
Methods
- Functions associated with a structs.
- Used to compute the area and return the name of each shape
Interfaces
- Defines a set of method signatures that structs must implement.
- Used to enforce a consistent API across different shape types.
Building the Geometry Tracker
- Define the Shape Interface
// Shape interface for all geometric figures
type Shape interface {
Area() float64
Name() string
String() string
}
Go2 . Implementing Structs for Shapes
// Circle struct
type Circle struct {
Radius float64
}
type Recatangle struct {
Width, Height float64
}
Go3 . Implementing Methods for Shapes
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Name() string {
return "Circle"
}
func (c Circle) String() string {
return fmt.Sprintf("%s (Radius: %.2f, Area: %.2f)":, c.Name(), c,Raduis, c.Area())
}
func (r Rectangle) Area() float64 {
return r.width * r.Height
}
func (r Rectangle) Name() string {
return "Rectangle"
}
func (r Rectangle) String() string {
return fmt.Sprintf("%s (Width: %.2f, Height: %.2f, Area: %.2f)", r.Name(), r.width, r.Height, r.Area())
}
Go4 . Creating the Geometry Tracker
type GeometryTracker struct {
Shapes []Shape // Stores multiple shapes
AreaLookup map[string]float64 // Tracks total area per shape type
}
// AddShape method
func (gt *GeometryTracker) AddShape(s Shape) {
gt.Shapes = append(gt.Shapes, s)
gt.AreaLookup[s.Name()] += s.Area()
}
// TotalArea method
func (gt GeometryTracker) TotalArea() float64 {
total := 0.0
for _, shape := range gt.Shapes {
total += shape.Area()
}
return total
}
// Display all shapes
func (gt GeometryTracker) DisplayShapes() {
for _, shape := range gt.Shapes {
fmt.Println(shape)
}
fmt.Println("\nTotal Area:", gt.TotalArea())
GoRunning the Program
func main() {
tracker := GeometryTracker{
Shapes: []Shape{},
AreaLookup: make(map[string]float64),
}
// Add shapes
tracker.AddShape(Circle{Radius: 5})
tracker.AddShape(Rectangle{Width: 4, Height: 6})
tracker.AddShape(Circle{Radius: 3})
// Display all shapes
tracker.DisplayShapes()
// Print area breakdown
fmt.Println("\nArea Breakdown:")
for shape, area := range tracker.AreaLookup {
fmt.Printf("%s: %.2f\n", shape, area)
}
}
GoExample output
Circle (Radius: 5.00, Area: 78.54)
Rectangle (Width: 4.00, Height: 6.00, Area: 24.00)
Circle (Radius: 3.00, Area: 28.27)
Total Area: 130.81
Area Breakdown:
Circle: 106.81
Rectangle: 24.00
For the “Geometry Tracker” mini-project, the architecture follows a modular and extensible design based on Go’s core principles. Let’s break it down:
1. Architectural Style: Modular & Interface-Based Design
• Uses structs and interfaces to model geometric shapes.
• Leverages slices to store multiple shape instances.
• Implements maps for efficient lookup and area tracking.
• Applies method chaining for better usability.
• Utilizes the Stringer interface for human-readable output.
2. Layered Structure
a) Data Layer (Structs & Fields)
• Defines the Circle and Rectangle structs to represent geometric shapes.
• Uses fields for dimensions (e.g., radius for circles, width & height for rectangles).
b) Behavior Layer (Methods & Interfaces)
• Implements a Shape interface with a Area() method for polymorphism.
• Implements String() using the fmt.Stringer interface for meaningful output.
c) Storage & Processing Layer
• Uses a slice ([]Shape) to store multiple shape instances dynamically.
• Uses a map (map[string]float64) to efficiently track shape names and their computed areas.
d) Application Layer (Main Logic)
• Initializes shapes.
• Stores them in the slice.
• Computes and prints total areas.
• Formats output for clarity.
3. Design Patterns & Principles Used
✅ Encapsulation – Shapes have private fields accessed via methods.
✅ Polymorphism – The Shape interface allows different types of shapes to be processed uniformly.
✅ Composition over Inheritance – No deep inheritance trees, just simple struct-based composition.
✅ Separation of Concerns – Data (structs), logic (methods), and storage (slices/maps) are cleanly separated.
✅ Open/Closed Principle – New shapes (e.g., Triangle) can be added without modifying existing code.
4. Final Folder Structure (If Extended into a Larger Project)
geometry-tracker/
│── main.go # Entry point for the application
│── shapes/
│ │── shape.go # Defines the Shape interface
│ │── circle.go # Implements the Circle struct & methods
│ │── rectangle.go # Implements the Rectangle struct & methods
│── storage/
│ │── store.go # Manages slices/maps for shape storage
│── utils/
│ │── format.go # Helper functions for formatting & output
│── go.mod # Go module file
Leave a Reply