Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleFlipkartMicrosoft

Prototype Pattern - Deep Copy vs Shallow Copy

Choose your preparation mode3 modes available
▶
Steps
setup

Define Profile class with fields and methods

The Profile class is defined with two fields: name (string) and scores (list). The __deepcopy__ method is declared but not yet executed.

💡 Understanding the class structure is essential because the copy behavior depends on how fields are handled in the clone method.
Line:class Profile: def __init__(self, name, scores): self.name = name self.scores = scores
💡 The Profile class holds nested mutable data (scores list), which is critical for demonstrating shallow vs deep copy.
📊
Prototype Pattern - Deep Copy vs Shallow Copy - Watch the Algorithm Execute, Step by Step
Watching each step of copying and cloning reveals the difference between shallow and deep copy, which is often confusing when only reading code.
Step 1/12
·Active fill★Answer cell
Class encapsulates data and cloning behavior for prototype pattern
Profile
+name: string
+scores: list[int]
+__init__()
+__deepcopy__()
Object instantiation from class
Profile
+name: string
+scores: list[int]
+__init__()
+__deepcopy__()
original
+name: string
+scores: list[int]
original → Profile (1:1)
Method activation during cloning
Profile
+name: string
+scores: list[int]
+__init__()
+__deepcopy__()
original
+name: string
+scores: list[int]
original → Profile (1:1)
Deep copy handles immutable fields efficiently
Profile
+name: string
+scores: list[int]
+__deepcopy__()
Recursive deep copy of nested mutable objects
Profile
+name: string
+scores: list[int]
+__deepcopy__()
scores
+0: int
+1: int
Profile ◆ scores (1:2)
New object instantiation with deep copied data
Profile
+name: string
+scores: list[int]
+__deepcopy__()
copy_obj
+name: string
+scores: list[int]
copy_obj → Profile (1:1)
Reading object state
original
+name: string
+scores: list[int]
Reading copy object state
copy_obj
+name: string
+scores: list[int]
Modifying nested data in copy
copy_obj
+name: string
+scores: list[int]
Verifying original object state after copy modification
original
+name: string
+scores: list[int]
Verifying copy object state after modification
copy_obj
+name: string
+scores: list[int]
Conceptual difference between shallow and deep copy
Profile
+name: string
+scores: list[int]
original
+scores: list[int]
shallow_copy
+scores: list[int]
original → Profile (1:1)shallow_copy → Profile (1:1)original → shallow_copy (1:1)

Key Takeaways

✓ Deep copy creates fully independent nested objects, preventing side effects when the copy is modified.

This is hard to see from code alone because nested references look similar; watching the copy of each nested object clarifies this.

✓ Immutable fields like strings do not require new memory allocation during deep copy, optimizing performance.

Understanding this helps learners see why deep copy is selective and efficient.

✓ Shallow copy shares nested references, so modifying the copy affects the original, which can cause bugs.

Seeing the conceptual difference visually helps learners grasp why deep copy overrides are necessary.

Practice

(1/5)
1. When a client calls a method on a Proxy object that controls access to a resource-intensive service, what is the typical sequence of events that occurs internally?
easy
A. Proxy performs access control, then lazily initializes the real service if needed, and finally forwards the call
B. Proxy immediately forwards the call to the real service without any checks
C. Proxy modifies the request parameters before forwarding to the real service
D. Proxy creates a simplified interface hiding the complexity of the real service

Solution

  1. Step 1: Understand Proxy's role

    Proxy controls access and may delay creation of the real service (lazy initialization).
  2. Step 2: Trace the call flow

    Client calls Proxy -> Proxy checks access -> Proxy creates real service if not already created -> Proxy forwards call -> Real service executes.
  3. Step 3: Eliminate incorrect options

    B is incorrect because Proxy usually adds control logic before forwarding. C is incorrect as Proxy typically does not modify parameters (that's Decorator or Adapter). D describes Facade, not Proxy.
  4. Final Answer:

    Option A -> Option A
Hint: Proxy = gatekeeper + lazy loader
Common Mistakes:
  • Assuming Proxy always forwards calls immediately without checks
  • Confusing Proxy with Facade's simplification role
  • Thinking Proxy modifies request parameters
2. Which of the following is a common trade-off when using a Facade pattern in a large system?
medium
A. Facade can hide too much complexity, making it hard to access advanced features of subsystems
B. Facade increases coupling between client and subsystems by exposing detailed interfaces
C. Facade always adds significant runtime overhead due to extra method calls
D. Facade requires changing the underlying subsystem interfaces to work properly

Solution

  1. Step 1: Recall Facade's purpose

    Facade simplifies complex subsystems by providing a unified interface.
  2. Step 2: Analyze trade-offs

    While Facade simplifies usage, it can hide advanced features, limiting flexibility.
  3. Step 3: Evaluate other options

    A is incorrect because Facade reduces coupling by hiding subsystem details. C is incorrect; Facade's overhead is minimal. D is wrong; Facade does not require changing subsystems.
  4. Final Answer:

    Option A -> Option A
Hint: Facade hides complexity but may hide power
Common Mistakes:
  • Believing Facade increases coupling instead of reducing it
  • Assuming Facade adds heavy runtime overhead
  • Thinking Facade requires modifying subsystems
3. Which of the following statements about handling concurrency in the Library Management System's LoanManager is INCORRECT?
medium
A. Optimistic locking is unsuitable because it always leads to deadlocks in high contention scenarios.
B. Using pessimistic locking on book records ensures no two users can borrow the same book simultaneously.
C. Implementing atomic check-and-update operations prevents race conditions during loan processing.
D. Using version numbers or timestamps can help detect conflicting updates in optimistic concurrency control.

Solution

  1. Step 1: Understand pessimistic locking

    Pessimistic locking prevents concurrent conflicting access, so Using pessimistic locking on book records ensures no two users can borrow the same book simultaneously. is correct.
  2. Step 2: Why optimistic locking is not always deadlock?

    Optimistic locking is unsuitable because it always leads to deadlocks in high contention scenarios. is incorrect; optimistic locking reduces deadlocks by retrying on conflicts.
  3. Step 3: Atomic operations prevent race conditions

    Implementing atomic check-and-update operations prevents race conditions during loan processing. is correct and essential for concurrency safety.
  4. Step 4: Versioning aids optimistic concurrency

    Using version numbers or timestamps can help detect conflicting updates in optimistic concurrency control. correctly describes conflict detection mechanisms.
  5. Final Answer:

    Option A -> Option A
  6. Quick Check:

    Optimistic locking reduces deadlocks; it does not always cause them.
Hint: Optimistic locking avoids deadlocks by retrying, pessimistic locking blocks access [OK]
Common Mistakes:
  • Believing optimistic locking always causes deadlocks
  • Confusing locking types and their effects
  • Ignoring atomicity in concurrency control
4. If the Library Management System must support reserving books that are currently loaned out, which design change best handles the edge case where multiple users reserve the same book simultaneously?
hard
A. Let the User class maintain their own reservation list independently without central coordination.
B. Allow multiple reservations by updating the book's status to 'reserved' without tracking order.
C. Add a reservation queue in the LoanManager and process reservations in FIFO order with atomic updates.
D. Implement a polling mechanism where users repeatedly check book availability without reservations.

Solution

  1. Step 1: Why a reservation queue?

    FIFO queue ensures fairness and order in handling multiple reservations.
  2. Step 2: Why not multiple reservations without order?

    Allow multiple reservations by updating the book's status to 'reserved' without tracking order. causes ambiguity and race conditions in fulfilling reservations.
  3. Step 3: Why not user-maintained reservations?

    Let the User class maintain their own reservation list independently without central coordination. lacks centralized control, risking inconsistent reservation states.
  4. Step 4: Why not polling without reservations?

    Implement a polling mechanism where users repeatedly check book availability without reservations. leads to poor user experience and race conditions.
  5. Final Answer:

    Option C -> Option C
  6. Quick Check:

    Centralized, ordered reservation management with atomic updates handles concurrency and fairness.
Hint: Use a centralized FIFO reservation queue to handle concurrent reservations fairly [OK]
Common Mistakes:
  • Ignoring reservation order and fairness
  • Decentralizing reservation tracking
  • Relying on user polling instead of system-managed reservations
5. Suppose you want to extend the singleton pattern to allow multiple instances but limit the total number to a fixed maximum (e.g., a pool of 3 instances). Which approach best adapts the singleton pattern to this new requirement while maintaining thread safety and lazy initialization?
hard
A. Replace the singleton instance with a thread-safe pool that lazily creates up to the max number of instances on demand.
B. Use an enum with multiple enum constants representing each instance.
C. Synchronize the entire getInstance() method and create new instances each time until max is reached, then reuse the last one.
D. Use eager initialization to create all instances at class load time and store them in a static array.

Solution

  1. Step 1: Understand the new requirement

    Multiple instances allowed but capped; lazy initialization and thread safety still required.
  2. Step 2: Evaluate options

    Enum constants are fixed and static, not lazy. Synchronizing entire method causes performance issues and reusing last instance breaks fairness. Eager initialization wastes resources if instances are unused. A thread-safe pool lazily creating instances up to max fits all requirements.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Thread-safe lazy pool creation matches new constraints [OK]
Hint: Lazy thread-safe pool creation fits capped multiple instances [OK]
Common Mistakes:
  • Using enum for multiple instances
  • Synchronizing entire method unnecessarily
  • Eagerly creating all instances wasting resources
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard