README.md
and passing tests.You’ll build a small, testable Java 17 app that demonstrates packages, interfaces, encapsulation, and access control (Module 1 core skills). You’ll also practice directory structure, basic testing, and a minimal CLI (or `main`) entry point.
project/
README.md
pom.xml (or build.gradle)
src/
main/
java/
com/yourname/oop/module1/
App.java
model/
service/
repo/
test/
java/
com/yourname/oop/module1/
AppTest.java
Set your base package:com.yourname.oop.module1
(replaceyourname
)
model/Student
(id, name, email) - fields private, validate in constructor/setters.model/Course
(code, title).model/Enrollment
(studentId, courseCode, status).
// repo/Repository.java
package com.yourname.oop.module1.repo;
import java.util.*;
public interface Repository<T, ID> {
T save(T entity);
Optional<T> findById(ID id);
List<T> findAll();
boolean deleteById(ID id);
}
// repo/InMemoryRepository.java
package com.yourname.oop.module1.repo;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class InMemoryRepository<T, ID> implements Repository<T, ID> {
private final Map<ID, T> store = new ConcurrentHashMap<>();
private final java.util.function.Function<T, ID> idExtractor;
public InMemoryRepository(java.util.function.Function<T, ID> idExtractor) {
this.idExtractor = Objects.requireNonNull(idExtractor);
}
@Override public T save(T entity) {
ID id = idExtractor.apply(entity);
if (id == null) throw new IllegalArgumentException("Entity id cannot be null");
store.put(id, entity);
return entity;
}
@Override public Optional<T> findById(ID id) { return Optional.ofNullable(store.get(id)); }
@Override public List<T> findAll() { return new ArrayList<>(store.values()); }
@Override public boolean deleteById(ID id) { return store.remove(id) != null; }
}
service/EnrollmentService
that uses repositories to enroll a student, list enrollments, drop course, etc.App.java
): minimal CLI / demo that:
System.out.println
is fine.
// App.java
package com.yourname.oop.module1;
import com.yourname.oop.module1.model.*;
import com.yourname.oop.module1.repo.*;
import java.util.*;
public class App {
public static void main(String[] args) {
Repository<Student, String> students =
new InMemoryRepository<>(Student::id);
Repository<Course, String> courses =
new InMemoryRepository<>(Course::code);
students.save(new Student("s-1", "Ava", "ava@example.com"));
courses.save(new Course("CS101", "Intro to CS"));
System.out.println("Students: " + students.findAll().size());
System.out.println("Courses: " + courses.findAll().size());
}
}
// model/Student.java
package com.yourname.oop.module1.model;
import java.util.Objects;
public final class Student {
private final String id;
private String name;
private String email;
public Student(String id, String name, String email) {
this.id = Objects.requireNonNull(id);
setName(name);
setEmail(email);
}
public String id() { return id; }
public String name() { return name; }
public String email() { return email; }
public void setName(String name) {
if (name == null || name.isBlank()) throw new IllegalArgumentException("name");
this.name = name.trim();
}
public void setEmail(String email) {
if (email == null || !email.contains("@")) throw new IllegalArgumentException("email");
this.email = email.trim();
}
}
// AppTest.java
package com.yourname.oop.module1;
import com.yourname.oop.module1.model.Student;
import com.yourname.oop.module1.repo.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class AppTest {
@Test
void canSaveAndFindStudent() {
Repository<Student, String> students = new InMemoryRepository<>(Student::id);
Student s = new Student("s-1", "Ava", "ava@example.com");
students.save(s);
assertTrue(students.findById("s-1").isPresent());
}
}
Build/Run:
mvn -q -DskipTests=false test && mvn -q -DskipTests package
./gradlew test build
model
: make fields private
, expose behavior/getters.App
thin; move rules to services.com.yourname.oop.module1.*
with clear subpackages.README.md
(how to build/run; your design notes)com/yourname/oop/module1/...
module1-project-yourname.zip
Repository<T,ID>
interface?package-private
preferable to public
?