Lesson Completion
Back to course

Architectural Patterns: MVC, MVP, MVVM, Dependency Injection, Repository

Beginner
12 minutes4.9Java

1. The Hook (The "Byte-Sized" Intro)

  • In a Nutshell: MVC = Model (data) + View (UI) + Controller (logic), MVP = MVC variant (Presenter replaces Controller, testable), MVVM = Model + View + ViewModel (data binding), Dependency Injection = inject dependencies (loose coupling), Repository = data access abstraction.
  • Benefits: Separation of concerns, testability, maintainability.
  • Use: MVC for web apps, MVP for testable UI, MVVM for data-binding frameworks, DI everywhere, Repository for data access!

MVC = restaurant (kitchen=Model, menu=View, waiter=Controller). MVP = theatre (actors=Model, audience=View, director=Presenter). DI = hiring (company doesn't train employees, hires trained ones). Repository = library (abstract away book storage)!


2. Conceptual Clarity (The "Simple" Tier)

💡 The Analogy

  • MVC: Restaurant service flow
  • DI: Power outlet (plug in any device)
  • Repository: Storage warehouse (hide how items are stored)

3. Technical Mastery (The "Deep Dive")

java
// =========================================== // 1. MVC PATTERN // =========================================== // Model (data + business logic) class UserModel { private String name; private String email; String getName() { return name; } void setName(String name) { this.name = name; } String getEmail() { return email; } void setEmail(String email) { this.email = email; } } // View (presentation) class UserView { void displayUser(String name, String email) { System.out.println("Name: " + name); System.out.println("Email: " + email); } } // Controller (mediates Model + View) class UserController { private UserModel model; private UserView view; UserController(UserModel model, UserView view) { this.model = model; this.view = view; } void setUserName(String name) { model.setName(name); } void updateView() { view.displayUser(model.getName(), model.getEmail()); } } // Usage: UserModel model = new UserModel(); model.setName("Alice"); model.setEmail("alice@example.com"); UserView view = new UserView(); UserController controller = new UserController(model, view); controller.updateView(); // =========================================== // 2. DEPENDENCY INJECTION // =========================================== // ❌ BAD: Tight coupling class EmailService { void send(String message) { System.out.println("Email: " + message); } } class Notification { private EmailService emailService = new EmailService(); // ❌ Tightly coupled! void notify(String message) { emailService.send(message); } } // ✅ GOOD: Dependency Injection interface MessageService { void send(String message); } class EmailService implements MessageService { public void send(String message) { System.out.println("Email: " + message); } } class SMSService implements MessageService { public void send(String message) { System.out.println("SMS: " + message); } } class Notification { private MessageService messageService; // Constructor injection Notification(MessageService messageService) { this.messageService = messageService; } void notify(String message) { messageService.send(message); } } // Usage: MessageService emailService = new EmailService(); Notification notif = new Notification(emailService); // Inject dependency! notif.notify("Hello"); // Switch to SMS easily: MessageService smsService = new SMSService(); Notification smsNotif = new Notification(smsService); // =========================================== // 3. REPOSITORY PATTERN // =========================================== // Entity class User { private int id; private String name; User(int id, String name) { this.id = id; this.name = name; } int getId() { return id; } String getName() { return name; } } // Repository interface interface UserRepository { User findById(int id); List<User> findAll(); void save(User user); void delete(int id); } // Concrete repository (in-memory) class InMemoryUserRepository implements UserRepository { private Map<Integer, User> users = new HashMap<>(); public User findById(int id) { return users.get(id); } public List<User> findAll() { return new ArrayList<>(users.values()); } public void save(User user) { users.put(user.getId(), user); } public void delete(int id) { users.remove(id); } } // Concrete repository (database) class DatabaseUserRepository implements UserRepository { public User findById(int id) { // SELECT * FROM users WHERE id = ? return null; // Simplified } public List<User> findAll() { // SELECT * FROM users return null; // Simplified } public void save(User user) { // INSERT INTO users ... } public void delete(int id) { // DELETE FROM users WHERE id = ? } } // Service layer uses repository class UserService { private UserRepository repository; UserService(UserRepository repository) { this.repository = repository; } void createUser(String name) { User user = new User(1, name); repository.save(user); } User getUser(int id) { return repository.findById(id); } } // Usage: Switch between in-memory and database easily! UserRepository repo = new InMemoryUserRepository(); UserService service = new UserService(repo); service.createUser("Alice"); User user = service.getUser(1);

5. The Comparison & Decision Layer

PatternUse When
MVCWeb applications, clear separation of concerns
MVPTestable UI (presenter can be unit tested)
MVVMData-binding frameworks (Angular, WPF)
Dependency InjectionAlways! (loose coupling, testability)
RepositoryAbstract data access layer

6. The "Interview Corner" (The Edge)

The "Killer" Interview Question: "Benefits of Dependency Injection?" Answer:

  1. Loose coupling: Change implementation without modifying client
  2. Testability: Inject mocks for testing
  3. Flexibility: Switch implementations easily
java
// Without DI: Hard to test class Service { private Database db = new Database(); // Can't inject mock! } // With DI: Easy to test class Service { private Database db; Service(Database db) { this.db = db; } // Inject mock! } // Test: Database mockDb = mock(Database.class); Service service = new Service(mockDb); // ✅ Testable!

Pro-Tip: Spring Framework DI:

java
@Service class UserService { @Autowired // Spring injects dependency! private UserRepository repository; } // Spring container manages dependencies // No manual 'new' keyword needed!

Topics Covered

Java Fundamentals

Tags

#java#programming#beginner-friendly

Last Updated

2025-02-01