Object-Oriented Programming Solutions for Real-World Logistics
@jaelDS
Fleet Management & Shipment Management
@PatrickGP23
Menu System & Integration
Purpose: Develop a comprehensive logistics management system using OOP principles to streamline fleet operations, customer management, and delivery tracking.
Problem Addressed: Manual tracking inefficiencies, data inconsistency, and lack of scalable architecture in traditional logistics operations.
Key Requirements: Australian address compliance, O(1) data retrieval performance, modular architecture, and secure unique identifiers.
The following diagram illustrates the architectural transformation from a procedural design (FMS) to a comprehensive object-oriented design (LMS):
+------------------------------- FMS (Procedural) ------------------------------+ +-------------------------------- LMS (OOP) --------------------------------+
| | | |
| +------------------+ | | +------------------+ |
| | main() | | | | MainMenu | |
| +--------+---------+ | | +--------+---------+ |
| | | | | |
| v | | v |
| +------------------+ | | +------------------+ |
| | function-based | | | | Menu Base | |
| | menu | | | | Class |<--------------------------+ |
| +--------+---------+ | | +--------+---------+ | |
| | | | | | |
| v | | | | |
| +------------------+ | | | Inheritance | |
| | Global Lists | | | | Hierarchy | |
| | +--------------+ | | | v | |
| | |vehicles_list | | | | +-----+-------+-------+-----+ | |
| | |shipment_list | | | | | | | | | | |
| | |delivery_list | | | | | | | | | | |
| | +--------------+ | | | v v v v v | |
| +--------+---------+ | | +---------+ +---------+ +---------+ +---------+ | |
| | | | |FleetMenu| |CustomerM| |ShipmentM| |DeliveryM| | |
| v +---------------+ | | +----+----+ +----+----+ +----+----+ +----+----+ | |
| +------------------+ | Input/Output | | | | | | | | |
| | Procedural |<--------------+ Validation | | | | | | | | |
| | Functions | | Functions | | | | | | | | |
| | +--------------+ | +---------------+ | | | | | | | |
| | |add_vehicle() | | | | | | | | | |
| | |track_ship() | | +---------------+ | | v v v v | |
| | |record_deliv()| |<--------------+ Data Access | | | +---------+ +---------+ +---------+ +---------+ | |
| | +--------------+ | | Functions | | | |DataStore| |DataStore| |DataStore| |DataStore| | |
| +------------------+ +---------------+ | | |(Vehicle)| |(Customer| |(Shipment| |(Delivery| | |
| | | +---------+ +---------+ +---------+ +---------+ | |
| | | | |
| No Encapsulation / Limited Code Reuse | | Data Objects | |
| | | +---------+ +---------+ +---------+ +---------+ | |
| +------------------+ | | | Vehicle | |Customer | |Shipment | |Delivery |-+ |
| | Limited | | | | Class | | Class | | Class | | Class | |
| | Extensibility | | | +---------+ +---------+ +---------+ +---------+ |
| +------------------+ | | |
| | | Encapsulation + Inheritance + Polymorphism |
+-------------------------------------------------------------------------------+ +-----------------------------------------------------------------------------+
Key Advantages of OOP Design:
- Modularity: Each class has a single responsibility
- Encapsulation: Data and methods are bundled together
- Inheritance: Code reuse through class hierarchies
- Polymorphism: Same interface, different implementations
- Extension: New features can be added with minimal changes
- Maintainability: Easier to modify and debug separate components
Our team conducted extensive research on software design principles to ensure robust implementation. Design patterns provide standardized, reusable solutions to recurring problems in software design, as discussed by Gamma et al. [1].
Design patterns define solutions to "repeatedly presenting issue during software designing" [1] and help communicate architectural knowledge between developers. These patterns also help "designers avoid traps and pitfalls that have traditionally been learned only by costly experiences" [1].
View IEEE SourceSoftware patterns "are examples of tried-and-true solutions and practice guidelines that can assist in transforming software engineering into a profession" [2]. These patterns can be incorporated at any stage of development to improve system design.
View IEEE SourceClean code is code that is "easy to read, understand, and maintain" [3]. Following clean code principles in Python helps "emphasize readability, simplicity, and maintainability" as outlined in modern software development practices [3].
View SourcePython data structures provide standardized, efficient methods for storing and organizing information. Open Data Structures presents foundational concepts with a "mathematically rigorous approach that is fast, practical, and efficient" [5], balancing classical topics with state-of-the-art implementations.
View SourceVersion control, code reviews, issue tracking
Video meetings, screen sharing, documentation
Quick updates, problem solving, daily communication
Our team implemented clean code principles [3] throughout our development workflow, focusing on readability and maintainability. This approach aligns with Martin's recommendation that code should be "read and enhanced by a developer other than its original author" [4]. Our team was in constant communication through WhatsApp as needed, however the project was managed greatly on Github. OOP Transportation Program Project.
In Python, dictionaries provide O(1) lookup performance using hash tables, making them ideal for our key-value data storage requirements [5]. As the Open Data Structures documentation confirms, this allows for efficient data retrieval based on unique identifiers.
| Operation | Dictionary | List | Our Choice |
|---|---|---|---|
| Lookup by ID | O(1) average | O(n) | Dictionary ✓ |
| Memory Usage | Higher | Lower | Acceptable trade-off |
| Scalability | Excellent | Limited | Dictionary ✓ |
Our DataStore implementation follows the principles of abstraction and encapsulation as outlined in common OOP design patterns [2].
class DataStore:
"""Central data management using dictionary for O(1) operations"""
def __init__(self):
self.data = {} # Hash table for efficient lookups
def add(self, item):
# Generate unique ID with type prefix
if isinstance(item, Vehicle):
prefix = "V"
elif isinstance(item, Customer):
prefix = "C"
# Create secure random ID
item_id = f"{prefix}{random_string}"
self.data[item_id] = item
return item_id
{
"CXHSG451": {
"id": "CXHSG451",
"name": "Acme Industries Ltd.",
"contact": "+61 4 1234 5678",
"address": "123 Main St, Brisbane, QLD",
"shipment_ids": ["S7GHI321", "SABC789F"]
},
"C5XY2AB": {
"id": "C5XY2AB",
"name": "Brisbane Logistics Co.",
"contact": "+61 7 8765 4321",
"address": "456 Queen St, Brisbane, QLD",
"shipment_ids": ["S123XYZ7"]
},
"C7DEF456": {
"id": "C7DEF456",
"name": "Queensland Suppliers",
"contact": "+61 4 9876 5432",
"address": "789 Edward St, Brisbane, QLD",
"shipment_ids": []
}
}
We applied the four fundamental OOP principles as described by Gamma et al. [1] and Martin [3] and in class explained by Shazi Saremi:
Private attributes protect internal state while public methods provide controlled access.
Menu base class provides common functionality to all specialized menu types.
execute() method behaves differently in each menu subclass while maintaining consistent interface.
Each component has single responsibility, enabling parallel development and easy maintenance.
Customer personal data is encapsulated within the Customer class, with controlled access as recommended by Shazi:
class Customer:
def __init__(self, customer_id=None, name=None, contact=None, address=None):
# Private data attributes
self.id = customer_id
self.name = name
self.contact = contact
self.address = address
self.shipment_ids = []
# Controlled access through public method
def display_info(self):
"""Display customer information - controlled data exposure"""
print(f"Customer ID: {self.id}")
print(f"Name: {self.name}")
print(f"Contact: {self.contact}")
print(f"Address: {self.address}")
# Note: Internal data structure is hidden from external access
Base Menu class template inherited by FleetMenu, demonstrating the reuse of common functionality as described in design patterns literature [1] and in class:
class Menu:
"""Base Menu class that all submenus inherit from"""
def __init__(self, title):
self.title = title
self.options = []
self.quit_options = ['q', 'Q', 'quit', 'Quit', '0']
def add_option(self, option_num, description, function):
"""Common method for all menus"""
self.options.append({
'number': option_num,
'description': description,
'function': function
})
def display(self):
"""Common display logic"""
print(f"\n===== {self.title} =====")
for option in self.options:
print(f"{option['number']}. {option['description']}")
class FleetMenu(Menu):
"""Fleet Management Menu inherits from base Menu"""
def __init__(self, vehicle_store):
# Call parent class constructor
super().__init__("Fleet Management")
self.vehicle_store = vehicle_store
self.__status = "Available"
# Using inherited add_option method
self.add_option('1', 'Add a vehicle', self.add_vehicle)
self.add_option('2', 'Update vehicle information', self.update_vehicle)
self.add_option('3', 'Remove a vehicle', self.remove_vehicle)
# Inherited display() method is available automatically
The execute() method behaves differently in different menu classes, implementing polymorphism as described in class:
class Menu:
def execute(self):
"""Base execution logic - polymorphic behavior"""
while True:
self.display()
choice = input("\nSelect the menu to display: ")
if choice in self.quit_options:
print(f"Exiting {self.title}...")
break
# Find and execute selected option
selected = None
for option in self.options:
if choice == str(option['number']):
selected = option
break
if selected:
selected['function']() # Execute the specific function
else:
print("Invalid option. Please try again.")
class MainMenu(Menu):
def execute(self):
"""Overridden execute for main menu - different behavior"""
menu = MainMenu()
menu.execute()
print("Thank you for using the Logistics Management System. Goodbye!")
display_signature() # Additional behavior specific to MainMenu
Each module has a single responsibility, like the DataStore for data management, following the Single Responsibility Principle that Martin advocates [3]:
class DataStore:
"""Single responsibility: Manage data storage and retrieval"""
def __init__(self):
self.data = {}
def add(self, item):
"""Only handles adding items"""
item_id = self._generate_id(item)
self.data[item_id] = item
return item_id
def find(self, item_id):
"""Only handles finding items"""
return self.data.get(item_id)
def remove(self, item_id):
"""Only handles removing items"""
if item_id in self.data:
del self.data[item_id]
return True
return False
# Each method has one clear purpose - modular design
This modular approach allowed me to work on Fleet Management while Michael developed the Menu System independently, with clean interfaces between components.
Learned how to effectively implement OOP principles to create modular, maintainable code that can be developed in parallel by team members, following the guidelines of Jiang et al. [1] and modern clean code practices [3].
Gained deep understanding of dictionary advantages and limitations [5]:
Discovered the importance of: