Below is a complete Kotlin program that demonstrates
Inheritance,
Composition, and
passing Mutable Lists between classes,
using Unified Modeling Language (UML) concepts to model a simple college system for Bradhurst College.
This example focuses on a educational theme, modeling a student course registry system with a
Catalog object (containing courses),
a StudentRegistry object (managing students), and a
Registrar object (controller for use cases).
The program includes the requested OOP concepts and UML relationships, tailored for a straightforward, student-friendly context.
Kotlin Code: Bradhurst College Course Registry System
import kotlin.random.Random
// 1. Inheritance: Base class for all entities in the system
open class Entity(val id: String) {
open fun describe(): String {
return "Entity ID: $id"
}
}
// 2. Composition and Inheritance: Course class inherits from Entity, contains no mutable lists directly
class Course(val name: String, val code: String, var credits: Int) : Entity(name) { // Added 'val' to name
init {
require(credits > 0) { "Credits must be positive" }
}
fun getDetails(): String {
return "$name ($code, $credits credits)" // Now 'name' is resolved as a property
}
override fun describe(): String {
return "${super.describe()}, Course: ${getDetails()}"
}
}
// 3. Composition and Inheritance: Student class inherits from Entity, contains a mutable list of courses
class Student(name: String, private var age: Int) : Entity(name) {
private val enrolledCourses = mutableListOf<Course>() // Composition: Student "has-a" list of Courses
init {
require(age >= 0) { "Age cannot be negative" }
}
// Public method to add a course (for Registrar to use)
fun enroll(course: Course) {
enrolledCourses.add(course)
println("${getName()} enrolled in ${course.getDetails()}")
}
// Public method to get courses (for passing to Registrar or printing)
fun getEnrolledCourses(): MutableList<Course> = enrolledCourses
// Getter for name (encapsulation)
fun getName(): String = id
// Getter and setter for age (encapsulation)
fun getAge(): Int = age
fun setAge(newAge: Int) { if (newAge >= 0) age = newAge }
override fun describe(): String {
return "${super.describe()}, Age: $age, Courses: ${enrolledCourses.size}"
}
}
// 4. Composition: Catalog class manages a mutable list of courses
class Catalog {
private val courses = mutableListOf<Course>()
// Add a course to the catalog
fun addCourse(course: Course) {
courses.add(course)
println("Added ${course.getDetails()} to catalog")
}
// Get courses (mutable list passed to other objects)
fun getCourses(): MutableList<Course> = courses
}
// 5. Composition: StudentRegistry manages a mutable list of students
class StudentRegistry {
private val students = mutableListOf<Student>()
// Add a student to the registry
fun addStudent(student: Student) {
students.add(student)
println("Added ${student.getName()} to registry")
}
// Get students (mutable list passed to other objects)
fun getStudents(): MutableList<Student> = students
// Print schedules for all students
fun printAllSchedules() {
students.forEach { student ->
println("\nSchedule for ${student.getName()}:")
if (student.getEnrolledCourses().isEmpty()) {
println("${student.getName()} has no enrolled courses.")
} else {
student.getEnrolledCourses().forEach { course ->
println(" - ${course.getDetails()}")
}
}
}
}
// Print schedule for a specific student
fun printStudentSchedule(studentName: String) {
val student = students.find { it.getName() == studentName }
if (student != null) {
println("\nSchedule for $studentName:")
if (student.getEnrolledCourses().isEmpty()) {
println("$studentName has no enrolled courses.")
} else {
student.getEnrolledCourses().forEach { course ->
println(" - ${course.getDetails()}")
}
}
} else {
println("Student $studentName not found in registry.")
}
}
}
// 6. Composition: Registrar acts as the controller for use cases
class Registrar {
private val catalog = Catalog()
private val registry = StudentRegistry()
// Use Case 1: Enroll a student in a course
fun enrollStudent(studentName: String, courseCode: String, credits: Int = 3) {
val student = registry.getStudents().find { it.getName() == studentName }
val course = catalog.getCourses().find { it.code == courseCode }
if (student != null && course != null) {
student.enroll(course)
} else {
println("Error: Student $studentName or Course $courseCode not found.")
}
}
// Use Case 2: Print schedule for all students
fun printAllSchedules() {
registry.printAllSchedules()
}
// Use Case 3: Print schedule for one specific student
fun printStudentSchedule(studentName: String) {
registry.printStudentSchedule(studentName)
}
// Initialize catalog and registry with sample data
fun initialize() {
// Add courses to catalog
catalog.addCourse(Course("Introduction to Programming", "CS101", 4))
catalog.addCourse(Course("Calculus I", "MATH101", 3))
catalog.addCourse(Course("History of Art", "ART201", 4))
catalog.addCourse(Course("Physics I", "PHY101", 3))
catalog.addCourse(Course("English Literature", "ENG101", 3))
catalog.addCourse(Course("Economics", "ECON101", 3))
// Add students to registry
registry.addStudent(Student("Alice", 20))
registry.addStudent(Student("Bob", 22))
registry.addStudent(Student("Charlie", 19))
}
}
// Main function to demonstrate use cases
fun main() {
val registrar = Registrar()
registrar.initialize()
// Use Case 1: Enroll 3 students in varying ways across 6 courses
registrar.enrollStudent("Alice", "CS101") // Alice enrolls in Introduction to Programming
registrar.enrollStudent("Alice", "MATH101") // Alice enrolls in Calculus I
registrar.enrollStudent("Bob", "ART201") // Bob enrolls in History of Art
registrar.enrollStudent("Bob", "PHY101") // Bob enrolls in Physics I
registrar.enrollStudent("Charlie", "ENG101") // Charlie enrolls in English Literature
registrar.enrollStudent("Charlie", "ECON101") // Charlie enrolls in Economics
registrar.enrollStudent("Charlie", "CS101") // Charlie enrolls in Introduction to Programming (3 courses total)
// Use Case 2: Print schedule for all students
registrar.printAllSchedules()
// Use Case 3: Print schedule for one specific student
registrar.printStudentSchedule("Alice")
}
Output (Sample)
Added Introduction to Programming (CS101, 4 credits) to catalog
Added Calculus I (MATH101, 3 credits) to catalog
Added History of Art (ART201, 4 credits) to catalog
Added Physics I (PHY101, 3 credits) to catalog
Added English Literature (ENG101, 3 credits) to catalog
Added Economics (ECON101, 3 credits) to catalog
Added Alice to registry
Added Bob to registry
Added Charlie to registry
Alice enrolled in Introduction to Programming (CS101, 4 credits)
Alice enrolled in Calculus I (MATH101, 3 credits)
Bob enrolled in History of Art (ART201, 4 credits)
Bob enrolled in Physics I (PHY101, 3 credits)
Charlie enrolled in English Literature (ENG101, 3 credits)
Charlie enrolled in Economics (ECON101, 3 credits)
Charlie enrolled in Introduction to Programming (CS101, 4 credits)
Schedule for Alice:
- Introduction to Programming (CS101, 4 credits)
- Calculus I (MATH101, 3 credits)
Schedule for Bob:
- History of Art (ART201, 4 credits)
- Physics I (PHY101, 3 credits)
Schedule for Charlie:
- English Literature (ENG101, 3 credits)
- Economics (ECON101, 3 credits)
- Introduction to Programming (CS101, 4 credits)
Schedule for Alice:
- Introduction to Programming (CS101, 4 credits)
- Calculus I (MATH101, 3 credits)
UML Diagram Description (Conceptual)
Here’s a textual description of the UML diagram for this system, which you can sketch or generate using tools like StarUML or draw.io. This will help visualize the relationships and guide students on how to model it:
Classes (Boxes with Compartments): Entity (Abstract Base Class):
Operations: describe(): String (open)
Inherits from Entity (dashed arrow with triangle from Course to Entity).
Attributes: code: String, credits: Int (private, with getters implied).
Operations: getDetails(): String, describe(): String (override).
Inherits from Entity (dashed arrow with triangle from Student to Entity). Attributes: age: Int (private, with getters/setters). Composition: enrolledCourses: MutableList<Course> (diamond arrow from Student to Course, labeled with multiplicity 0..*).
Operations: enroll(course: Course), getEnrolledCourses(): MutableList<Course>, getName(): String, getAge(): Int, setAge(newAge: Int), describe(): String (override).
Attributes: courses: MutableList<Course> (private, with getter getCourses()).
Operations: addCourse(course: Course), getCourses(): MutableList<Course>.
Attributes: students: MutableList<Student> (private, with getter getStudents()). Operations: addStudent(student: Student), getStudents(): MutableList<Student>, printAllSchedules(), printStudentSchedule(studentName: String).
Composition: catalog: Catalog, registry: StudentRegistry (diamond arrows from Registrar to Catalog and StudentRegistry). Operations: enrollStudent(studentName: String, courseCode: String, credits: Int = 3), printAllSchedules(), printStudentSchedule(studentName: String), initialize().
Inheritance: Course and Student inherit from Entity (generalization/specialization, dashed arrow with triangle).
Composition: Student "has-a" enrolledCourses (diamond arrow to Course), Catalog "has-a" courses (diamond to Course), StudentRegistry "has-a" students (diamond to Student), Registrar "has-a" catalog and registry (diamonds to Catalog and StudentRegistry).
Associations: Registrar interacts with Catalog and StudentRegistry via method calls (solid lines with arrows for operations like enrollStudent()).
Student to enrolledCourses: 0..* (zero or more courses per student).
Catalog to courses: 0..* (zero or more courses in catalog).
StudentRegistry to students: 0..* (zero or more students in registry).
Registrar to Catalog and StudentRegistry: 1 (exactly one instance each).
This UML diagram shows how Team A (e.g., developers designing the registrar system) can define Catalog, StudentRegistry, and Registrar with interfaces or abstract classes, while Team B (e.g., course or student developers) implements Course and Student later, passing mutable lists to ensure flexibility and collaboration.
Explanation of UML and Team Collaboration
Inheritance in UML: Entity as a base class ensures shared identity (id) across Course and Student, modeled with generalization. Team A can define Entity and expect Team B to extend it for specific entities, ensuring consistency.
Composition in UML: Diamond arrows show ownership (e.g., Student owns enrolledCourses), enabling Team A to design StudentRegistry and Catalog to manage lists, while Team B implements Course and Student to populate them.
Mutable Lists and Passing: UML associations with multiplicity (e.g., 0..*) model mutable lists passed between Catalog, StudentRegistry, and Registrar. Team A can write Registrar to operate on getCourses() and getStudents(), assuming Team B provides compliant implementations.
Team A and B Collaboration: Team A designs Registrar to call Catalog.getCourses() and StudentRegistry.getStudents(), using UML to specify interfaces or abstract methods. Even if Team B hasn’t implemented Course or Student, Team A can mock these classes or use interfaces (e.g., Bookable from Lab 10), ensuring parallel development for Bradhurst College’s system.
Talking Points for Lab Preview
Inheritance, composition, and mutable lists model Bradhurst College’s course system—Student inherits from Entity, composes courses, and passes lists to Registrar for use cases like enrolling in programming or art
UML diagrams let Team A design Registrar and Catalog before Team B implements Course and Student, ensuring modular, scalable systems for Bradhurst College.
This ties to Labs 5–10: inheritance (Lab 5), composition (Lab 9), interfaces (Lab 10), and encapsulation (Lab 8) for passing lists safely.
Instructor Notes
Tools: IntelliJ for code, projector for sharing, whiteboard or UML tool (e.g., StarUML) for diagrams.
Tie to Curriculum: Reference Labs 5–10, focusing on a relatable college theme (e.g., Bradhurst courses, students), and null safety (optional extension for mutable lists).
Next Steps: Transition to full labs on inheritance, composition, interfaces, and mutable lists, building on this preview.
This code and UML description provide a clear, practical introduction to modeling a simple college system with Kotlin and UML, aligning with your educational theme and curriculum.