Loading content...
Object identification is a skill, and like any skill, it develops through deliberate practice. You've learned the techniques: reading with an OO lens, extracting nouns as candidate objects, mapping verbs to methods, and filtering candidates into a refined class design.
Now it's time to put these techniques into practice. This page presents a series of increasingly complex exercises, each walking you through the complete process from requirements to initial object model. Work through each example actively—don't just read the solutions. Try to identify objects and methods yourself before checking the analysis.
True mastery comes when you can look at any problem statement and see the objects within it, almost effortlessly. That's our goal.
For each exercise: (1) Read the requirements carefully, (2) Extract nouns and verbs yourself, (3) Attempt to identify classes and methods, (4) Then compare your analysis to the provided solution. The goal isn't to match the solution exactly—reasonable designs can vary—but to develop your analytical thinking.
Before diving into exercises, let's consolidate the complete object identification process:
Your first pass won't be perfect. Expect to revisit and refine as you discover new information or recognize patterns you missed. The goal is a coherent model, not a perfect first draft.
Requirements:
"Design a restaurant ordering system where customers can view the menu, place orders, and pay their bill. The menu contains items organized into categories like appetizers, mains, and desserts. Each menu item has a name, description, price, and availability status. Customers can customize orders with special instructions (e.g., 'no onions'). Staff can update item availability and view pending orders. The system tracks orders from placement through preparation to serving."
Pause here and try to identify objects and methods yourself before continuing.
Analysis:
Step 1: Extract Nouns
From the requirements:
Step 2: Categorize and Filter
| Noun | Category | Decision |
|---|---|---|
| restaurant, ordering system | Context | ❌ System boundary |
| customers | Entity | ✅ User type |
| staff | Entity | ✅ User type with admin capabilities |
| menu | Entity | ✅ Contains categories and items |
| items (menu items) | Entity | ✅ Core domain object |
| categories | Entity | ✅ Groups menu items |
| appetizers, mains, desserts | Instances | ❌ Just category examples |
| name, description, price | Attributes | ❌ Properties of MenuItem |
| availability status | Attribute/Enum | ⚠️ Attribute of MenuItem |
| orders | Entity | ✅ Core transactional entity |
| bill | Entity | ⚠️ Possibly Order or OrderPayment |
| special instructions | Attribute | ❌ Property of OrderItem |
| placement, preparation, serving | States | ❌ States of Order (enum or status field) |
Step 3: Extract Verbs
Step 4: Assign Methods
| Verb | Method | Assigned To |
|---|---|---|
| view menu | getMenu() or getMenuItems() | Menu or MenuRepository |
| place orders | placeOrder(items) | OrderService or Customer |
| pay bill | pay(amount, method) | Order or PaymentService |
| customize | addSpecialInstructions(text) | OrderItem |
| update availability | setAvailability(status) | MenuItem |
| view pending orders | getPendingOrders() | OrderRepository |
| track | getStatus(), updateStatus() | Order |
Step 5: Final Class Model
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
// Usersclass Customer { id: string; name: string; placeOrder(items: OrderItem[]): Order; viewOrderHistory(): Order[];} class Staff { id: string; name: string; role: StaffRole; updateItemAvailability(item: MenuItem, status: boolean): void; viewPendingOrders(): Order[]; updateOrderStatus(order: Order, status: OrderStatus): void;} // Menu Domainclass Menu { categories: Category[]; getAvailableItems(): MenuItem[]; getItemsByCategory(category: Category): MenuItem[];} class Category { id: string; name: string; displayOrder: number; items: MenuItem[];} class MenuItem { id: string; name: string; description: string; price: Money; category: Category; isAvailable: boolean; setAvailability(available: boolean): void;} // Order Domainclass Order { id: string; customer: Customer; items: OrderItem[]; status: OrderStatus; createdAt: Date; addItem(menuItem: MenuItem, quantity: number): OrderItem; removeItem(orderItem: OrderItem): void; calculateTotal(): Money; updateStatus(status: OrderStatus): void; pay(paymentMethod: PaymentMethod): Payment;} class OrderItem { menuItem: MenuItem; quantity: number; specialInstructions: string; addSpecialInstructions(text: string): void; getSubtotal(): Money;} enum OrderStatus { PLACED, PREPARING, READY, SERVED, PAID, CANCELLED}Notice how 'bill' became part of Order (the pay() method and PAID status) rather than a separate class. Notice also how 'special instructions' lives on OrderItem, not Order—because customizations apply to specific items, not the whole order.
Requirements:
"Design an airline booking system where passengers can search for flights, select seats, and make reservations. Flights have a departure city, arrival city, date, time, and available seats. Seats are classified as economy, business, or first class with different prices. Passengers provide their personal information and contact details during booking. The system generates a confirmation with a booking reference number. Passengers can check-in online 24 hours before departure and receive a boarding pass. Airlines can add, modify, or cancel flights."
Attempt your analysis before reading on.
Analysis:
Key Design Decisions:
Flight vs FlightSchedule: 'Flights' might mean a specific flight on a specific date, or a recurring schedule. We're treating it as a specific flight instance (Flight 123 on Jan 15).
Seat belongs to Flight: Each Flight has its own seats with availability. A seat is not a global entity—it's 'Seat 12A on Flight 123 on Jan 15.'
Booking captures the relationship: Booking links Passenger to Flight and Seat, and tracks the lifecycle (confirmed → checked-in → boarded).
BoardingPass is generated, not created from scratch: It's derived from Booking at check-in time.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
class Flight { flightNumber: string; departureAirport: Airport; arrivalAirport: Airport; departureTime: DateTime; arrivalTime: DateTime; aircraft: Aircraft; seats: Seat[]; status: FlightStatus; getAvailableSeats(seatClass?: SeatClass): Seat[]; isAvailable(): boolean; cancel(): void; delay(newTime: DateTime): void;} class Seat { seatNumber: string; // e.g., "12A" seatClass: SeatClass; // ECONOMY, BUSINESS, FIRST price: Money; isAvailable: boolean; reserve(): void; release(): void;} class Booking { referenceNumber: string; // e.g., "ABC123" passenger: Passenger; flight: Flight; seat: Seat; status: BookingStatus; // CONFIRMED, CHECKED_IN, CANCELLED createdAt: DateTime; static create(passenger: Passenger, flight: Flight, seat: Seat): Booking; confirm(payment: Payment): void; checkIn(): BoardingPass; // Only available 24h before cancel(): CancellationResult; canCheckIn(): boolean;} class BoardingPass { booking: Booking; gate: string; boardingTime: DateTime; barcode: string; static generateFrom(booking: Booking): BoardingPass;} class Passenger { id: string; firstName: string; lastName: string; email: string; phone: string; passportNumber?: string; getBookings(): Booking[]; getUpcomingFlights(): Flight[];} class Airline { code: string; // e.g., "UA" name: string; addFlight(details: FlightDetails): Flight; cancelFlight(flight: Flight): void; modifyFlight(flight: Flight, changes: FlightChanges): void;} class FlightSearchService { search(criteria: FlightSearchCriteria): Flight[];}Aircraft wasn't mentioned but is implied (flights use planes with specific seat configurations). Airport emerged from 'city' but is more precise. Payment is implicit in booking confirmation. These implicit entities complete the model.
Requirements:
"Design a social media platform where users can create profiles, post content, and interact with others. Users can follow other users and see posts from people they follow in their feed. Posts can contain text, images, or videos. Users can like posts, leave comments, and share posts to their own profile. Comments can receive likes and replies. Users can send private messages to each other. The system notifies users of new followers, likes, and comments. Users can block other users, which prevents all interactions."
This is a complex system. Try identifying the core entities and their relationships.
Analysis:
Identified Classes:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
// User Domainclass User { id: string; username: string; profile: Profile; followers: User[]; following: User[]; blockedUsers: User[]; createPost(content: PostContent): Post; follow(user: User): void; unfollow(user: User): void; block(user: User): void; unblock(user: User): void; isBlocking(user: User): boolean; getFeed(): Post[]; // Posts from followed users sendMessage(to: User, content: string): Message;} class Profile { displayName: string; bio: string; profileImage: Media; coverImage: Media; update(details: ProfileDetails): void;} // Content Domainclass Post { id: string; author: User; content: PostContent; likes: Like[]; comments: Comment[]; shares: Share[]; createdAt: DateTime; visibility: PostVisibility; like(user: User): Like; unlike(user: User): void; addComment(user: User, text: string): Comment; share(user: User): Share; getLikeCount(): number; isLikedBy(user: User): boolean;} class PostContent { text: string; media: Media[]; // Images or videos} class Media { type: MediaType; // IMAGE, VIDEO url: string; thumbnailUrl: string;} class Comment { id: string; author: User; post: Post; parentComment?: Comment; // For replies text: string; likes: Like[]; createdAt: DateTime; reply(user: User, text: string): Comment; like(user: User): Like; unlike(user: User): void;} class Like { user: User; target: Post | Comment; createdAt: DateTime;} class Share { user: User; originalPost: Post; comment?: string; // Optional share caption createdAt: DateTime;} // Messaging Domainclass Message { id: string; sender: User; recipient: User; content: string; sentAt: DateTime; readAt?: DateTime; markAsRead(): void; isRead(): boolean;} class Conversation { participants: User[]; messages: Message[]; getLatestMessages(count: number): Message[]; sendMessage(from: User, content: string): Message;} // Notificationsclass Notification { id: string; recipient: User; type: NotificationType; // NEW_FOLLOWER, LIKE, COMMENT, MESSAGE data: NotificationData; createdAt: DateTime; readAt?: DateTime; markAsRead(): void;}| Relationship | Type | Implementation |
|---|---|---|
| User follows User | Many-to-many, self-reference | Following/followers collections |
| User blocks User | Many-to-many, self-reference | BlockedUsers collection |
| User authors Posts | One-to-many | Post.author reference |
| Users like Posts | Many-to-many | Like entity captures who and when |
| Comment replies to Comment | Self-reference, tree structure | parentComment reference |
| Users exchange Messages | Many-to-many | Message entity with sender/recipient |
Notice patterns: Like is an entity (not just a count) because we need to track who liked what and when. Comment uses a self-reference for nested replies. Block checking must happen before allowing interactions—this is a cross-cutting concern.
Requirements:
"Design a learning management system where instructors create courses with modules and lessons. Each lesson can contain videos, documents, and quizzes. Students enroll in courses and track their progress through the curriculum. Quizzes have multiple-choice and free-text questions; the system grades multiple-choice automatically but free-text requires instructor review. Students earn certificates upon completing all required lessons. Instructors can view analytics on student performance and engagement."
Analysis:
Core Objects Identified:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
// Course Structureclass Course { id: string; title: string; description: string; instructor: Instructor; modules: Module[]; addModule(module: Module): void; publish(): void; getEnrolledStudents(): Student[]; getCompletionRate(): number;} class Module { id: string; title: string; order: number; lessons: Lesson[]; addLesson(lesson: Lesson): void; reorderLessons(newOrder: string[]): void;} class Lesson { id: string; title: string; order: number; content: LessonContent[]; // Polymorphic isRequired: boolean; addContent(content: LessonContent): void;} // Lesson Content (Strategy/Polymorphism)interface LessonContent { type: ContentType; render(): void;} class VideoContent implements LessonContent { videoUrl: string; duration: number; transcript?: string;} class DocumentContent implements LessonContent { documentUrl: string; pageCount: number;} class Quiz implements LessonContent { questions: Question[]; passingScore: number; grade(submission: QuizSubmission): QuizResult;} // Questions (Polymorphism)abstract class Question { id: string; text: string; points: number; abstract grade(answer: Answer): number; abstract requiresManualGrading(): boolean;} class MultipleChoiceQuestion extends Question { options: string[]; correctAnswer: number; grade(answer: Answer): number { return answer.selectedOption === this.correctAnswer ? this.points : 0; } requiresManualGrading(): boolean { return false; }} class FreeTextQuestion extends Question { gradingRubric?: string; grade(answer: Answer): number { return -1; // Indicates manual grading needed } requiresManualGrading(): boolean { return true; }} // Enrollment and Progressclass Enrollment { student: Student; course: Course; enrolledAt: DateTime; progress: Progress; isCompleted(): boolean; getCompletionPercentage(): number; generateCertificate(): Certificate;} class Progress { completedLessons: Lesson[]; quizResults: QuizResult[]; markLessonComplete(lesson: Lesson): void; hasCompletedLesson(lesson: Lesson): boolean; hasPassedQuiz(quiz: Quiz): boolean;} class Certificate { student: Student; course: Course; issuedAt: DateTime; certificateNumber: string; static generate(enrollment: Enrollment): Certificate; download(): Blob;} // Usersclass Student { id: string; name: string; email: string; enrollments: Enrollment[]; enroll(course: Course): Enrollment; getProgress(course: Course): Progress; getCertificates(): Certificate[];} class Instructor { id: string; name: string; courses: Course[]; createCourse(details: CourseDetails): Course; viewAnalytics(course: Course): CourseAnalytics; gradeSubmission(submission: QuizSubmission, score: number): void;}Notice how Question uses inheritance: MultipleChoiceQuestion auto-grades while FreeTextQuestion requires manual review. LessonContent could be an interface with Video, Document, and Quiz implementations. This is the Strategy pattern enabling extensibility.
Through these exercises and real-world experience, certain patterns of mistakes emerge. Being aware of them helps you avoid them:
If one class has 20+ methods or knows about everything in the system, it's a 'God Object.' This usually means responsibilities weren't properly distributed. Break it down using the heuristics: what data does each method need? That's where the method should live.
Use this checklist to evaluate your object identification work:
Module Complete:
Congratulations! You've completed Module 2: Identifying Objects in Problem Statements. You now have the foundational skills to read any requirements document and extract a coherent object model—the backbone of object-oriented design.
Next Steps:
With objects identified, the next module explores how these objects relate to each other—exploring association, aggregation, composition, and dependency in depth.
You now have the complete toolkit for object identification: reading with an OO lens, extracting nouns as objects, mapping verbs to methods, and practicing with real-world examples. Apply these skills to every design problem you encounter to build lasting fluency.