Week 10 Lesson
Design Patterns Part 2: Adapter, Decorator, Command, Repository, MVC/MVVM
Some patterns help connect systems, extend behavior, and separate application layers.
Learning Objectives
- Use Adapter to connect incompatible interfaces.
- Use Decorator to add behavior around an object.
- Use Command to represent actions.
- Use Repository to separate persistence from business logic.
- Explain MVC and MVVM separation.
Lecture Notes
Adapter is used when one interface does not match what your code expects. Suppose your app expects a PaymentGateway with charge(amount), but a provider library exposes createPaymentIntent(valueInCents). An adapter translates between your stable application interface and the provider’s interface. This protects the rest of the system from provider-specific details.
Decorator adds behavior before or after another object without changing that object’s code. A NotifyingTaskRepository might wrap a normal TaskRepository and publish an event after saving. A CachedCatalogRepository might wrap a database repository and cache results. Decorator is useful when behavior should be layered flexibly.
Command turns an action into an object. This is useful for undo/redo, queues, logging, and menu actions. In a drawing app, DrawLineCommand and MoveShapeCommand can both execute and undo. In a task app, CompleteTaskCommand can represent a user action that can be stored in history.
Repository separates data access from business logic. A service should not need to know whether tasks are stored in memory, localStorage, SQLite, or an API. It asks a repository for tasks. This keeps business rules testable and makes storage easier to replace.
MVC, MVP, and MVVM are architectural presentation patterns. Their shared goal is separation between interface, state, and behavior. MVC separates Model, View, and Controller. MVVM often uses a ViewModel to expose state and commands to the View. The exact pattern matters less than the principle: UI code should not own every business rule.
Worked Example: Repository separates storage
class TaskService {
createTask(title: string) {
const tasks = JSON.parse(localStorage.getItem('tasks') || '[]');
tasks.push({ title, completed: false });
localStorage.setItem('tasks', JSON.stringify(tasks));
}
}interface TaskRepository {
findAll(): Task[];
save(task: Task): void;
}
class TaskService {
constructor(private repo: TaskRepository) {}
createTask(title: string) {
if (title.trim().length === 0) throw new Error('Title required');
this.repo.save({ title, completed: false });
}
}Lab: Repository and UI Separation
Scenario: A task tracker stores data directly inside button click handlers.
Steps
- Move validation into a service.
- Create a repository interface.
- Create one in-memory repository for tests.
- Keep UI handlers focused on user interaction.
- Explain how this resembles MVC or MVVM separation.
Deliverables
- Refactored code
- Repository interface
- Short architecture note
Assignment
Build a small app screen using a service and repository. The UI should not directly own business rules.
Discussion Prompts
- What does Adapter protect you from?
- When is Repository unnecessary?
- How much logic should live in the UI?
Week 10 Quiz
Use these as quick checks after the lesson.
Question 1
Adapter is used to:
Question 2
Decorator is useful when:
Question 3
Command represents:
Question 4
Repository separates:
Question 5
MVC/MVVM mainly help separate:
Student Notes
Saved in this browser only.