Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleFlipkartMicrosoft

Prototype Pattern - Deep Copy vs Shallow Copy

Choose your preparation mode3 modes available
🎯
Prototype Pattern - Deep Copy vs Shallow Copy
mediumOOPAmazonGoogleFlipkart

Imagine you have a complex object representing a user profile with nested preferences and settings. You want to create a copy of this profile to experiment with changes without affecting the original. How do you ensure the copy is independent?

💡 This problem deals with how to create copies of objects in object-oriented programming. Beginners often confuse shallow and deep copies, leading to bugs where changes to one object unexpectedly affect another. Understanding the difference is crucial for safe object cloning.
📋
Problem Statement

Given an object with nested objects or references, implement cloning functionality that supports both shallow copy and deep copy. The shallow copy duplicates the top-level object but shares references to nested objects, while the deep copy duplicates the entire object graph, creating independent nested objects. Implement and demonstrate both approaches.

Objects may contain nested objects or collectionsNested objects can be arbitrarily deepAvoid infinite loops in case of cyclic references (optional advanced)Focus on correctness over performance for deep copy
💡
Example
Input"Original object with nested list: obj = {name: 'A', scores: [10, 20]}"
OutputShallow copy: copy.scores is same reference as obj.scores; Deep copy: copy.scores is a new list with same values

In shallow copy, modifying copy.scores affects obj.scores; in deep copy, they are independent.

  • Object with no nested references → shallow and deep copy behave similarly
  • Object with nested mutable objects → shallow copy shares references, deep copy duplicates
  • Empty object or null references → copying should handle gracefully
  • Object with cyclic references (advanced) → deep copy must avoid infinite recursion
⚠️
Common Mistakes
Using shallow copy when deep copy is needed

Modifying nested objects in copy affects original, causing bugs

✅ Implement deep copy to duplicate nested objects

Modifying original after copying without realizing shared references

Unexpected side effects in copied object

✅ Use deep copy or avoid modifying shared nested objects

Not overriding clone or copy methods properly

Default shallow copy used, causing subtle bugs

✅ Override clone/copy methods to implement deep copy logic

Using JSON serialization for deep copy with functions or special objects

Loss of methods or incorrect copying

✅ Use custom clone methods or libraries that handle complex types

Ignoring cyclic references in deep copy

Infinite recursion or stack overflow

✅ Implement memoization to track visited objects during deep copy

🧠
Brute Force: Manual Shallow Copy Implementation
💡 Starting with a manual shallow copy helps understand what copying means at the object level and why it can be insufficient when nested objects are involved.

Intuition

Copy the top-level object fields directly, but nested objects remain shared references. This is simple but can cause side effects if nested objects are modified.

Algorithm

  1. Create a new object instance of the same class.
  2. Copy primitive fields and references of nested objects directly.
  3. Return the new object as the shallow copy.
💡 This approach is straightforward but does not handle nested objects properly, which is a common pitfall.
</>
Code
class Profile:
    def __init__(self, name, scores):
        self.name = name
        self.scores = scores  # list

    def shallow_copy(self):
        # Create a new Profile with same name and same scores reference
        return Profile(self.name, self.scores)

# Driver code
if __name__ == '__main__':
    original = Profile('Alice', [10, 20])
    copy = original.shallow_copy()
    print('Original scores:', original.scores)
    print('Copy scores:', copy.scores)
    copy.scores.append(30)
    print('After modifying copy scores:')
    print('Original scores:', original.scores)
    print('Copy scores:', copy.scores)
Line Notes
def shallow_copy(self):Defines the method to create a shallow copy of the object
return Profile(self.name, self.scores)Copies primitive and references directly, no new nested objects created
copy.scores.append(30)Modifies the nested list in the copy to show shared reference effect
print('Original scores:', original.scores)Shows that original object's nested list is affected by copy's modification
import java.util.*;
class Profile {
    String name;
    List<Integer> scores;

    Profile(String name, List<Integer> scores) {
        this.name = name;
        this.scores = scores;
    }

    Profile shallowCopy() {
        // Shallow copy: new Profile with same scores reference
        return new Profile(this.name, this.scores);
    }

    public static void main(String[] args) {
        List<Integer> scores = new ArrayList<>(Arrays.asList(10, 20));
        Profile original = new Profile("Alice", scores);
        Profile copy = original.shallowCopy();
        System.out.println("Original scores: " + original.scores);
        System.out.println("Copy scores: " + copy.scores);
        copy.scores.add(30);
        System.out.println("After modifying copy scores:");
        System.out.println("Original scores: " + original.scores);
        System.out.println("Copy scores: " + copy.scores);
    }
}
Line Notes
Profile shallowCopy() {Method to create a shallow copy of the Profile object
return new Profile(this.name, this.scores);Copies references directly, nested list is shared
copy.scores.add(30);Modifies the nested list in the copy to demonstrate shared reference
System.out.println("Original scores: " + original.scores);Shows original object's nested list is affected
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Profile {
public:
    string name;
    vector<int> scores;

    Profile(string n, vector<int> s) : name(n), scores(s) {}

    Profile shallowCopy() {
        // Note: In C++, vector copy is deep by default.
        // This means this method actually performs a deep copy of scores.
        // True shallow copy would require sharing pointer/reference, which is unsafe here.
        return Profile(name, scores); // Copies vector deeply in C++
    }
};

int main() {
    vector<int> scores = {10, 20};
    Profile original("Alice", scores);
    Profile copy = original.shallowCopy();
    cout << "Original scores: ";
    for (int x : original.scores) cout << x << " ";
    cout << endl;
    cout << "Copy scores: ";
    for (int x : copy.scores) cout << x << " ";
    cout << endl;
    copy.scores.push_back(30);
    cout << "After modifying copy scores:" << endl;
    cout << "Original scores: ";
    for (int x : original.scores) cout << x << " ";
    cout << endl;
    cout << "Copy scores: ";
    for (int x : copy.scores) cout << x << " ";
    cout << endl;
    return 0;
}
Line Notes
Profile shallowCopy() {Defines shallow copy method; vector copy is deep by default in C++
return Profile(name, scores);Returns new object with copied vector (actually deep copy in C++)
copy.scores.push_back(30);Modifies copy's scores vector to test independence
for (int x : original.scores)Prints original scores to check if affected by copy's modification
class Profile {
    constructor(name, scores) {
        this.name = name;
        this.scores = scores; // array reference
    }

    shallowCopy() {
        // Shallow copy: new object with same array reference
        return new Profile(this.name, this.scores);
    }
}

// Driver code
const original = new Profile('Alice', [10, 20]);
const copy = original.shallowCopy();
console.log('Original scores:', original.scores);
console.log('Copy scores:', copy.scores);
copy.scores.push(30);
console.log('After modifying copy scores:');
console.log('Original scores:', original.scores);
console.log('Copy scores:', copy.scores);
Line Notes
shallowCopy() {Defines shallow copy method returning new object with shared nested array
return new Profile(this.name, this.scores);Copies primitive and references directly, no new nested array
copy.scores.push(30);Modifies nested array in copy to show shared reference effect
console.log('Original scores:', original.scores);Shows original object's nested array is affected
⏱
Complexity
TimeO(1) since only references are copied, no nested objects duplicated
SpaceO(1) additional space as no new nested objects created

Shallow copy duplicates only top-level object; nested references remain shared, so copying is fast but risky. Note: In C++, vector copy is deep by default, so this approach behaves differently.

💡 For a nested list of size 1000, shallow copy just copies the reference instantly, so it's very fast but can cause bugs if nested objects are modified.
Interview Verdict: Accepted for shallow copy demonstration; insufficient for independent nested objects. Note: C++ vector copy is deep, so true shallow copy is not demonstrated here.

This approach is useful to introduce the concept but not safe for nested mutable objects. C++ behavior differs due to vector semantics.

🧠
Better: Deep Copy Using Recursion
💡 This approach introduces recursion to create independent copies of nested objects, solving the shared reference problem of shallow copy.

Intuition

Recursively copy each nested object or collection to create a fully independent clone of the entire object graph.

Algorithm

  1. Check if the field is a primitive or immutable; if yes, copy directly.
  2. If the field is a list or collection, create a new list and recursively deep copy each element.
  3. If the field is an object, recursively call deep copy on it.
  4. Return the new object with all fields deeply copied.
💡 Recursion can be tricky to implement correctly, especially handling different data types and avoiding infinite loops.
</>
Code
import copy

class Profile:
    def __init__(self, name, scores):
        self.name = name
        self.scores = scores

    def deep_copy(self):
        # Use recursion or copy.deepcopy
        new_scores = [score for score in self.scores]  # copy list elements
        return Profile(self.name, new_scores)

# Driver code
if __name__ == '__main__':
    original = Profile('Alice', [10, 20])
    copy = original.deep_copy()
    print('Original scores:', original.scores)
    print('Copy scores:', copy.scores)
    copy.scores.append(30)
    print('After modifying copy scores:')
    print('Original scores:', original.scores)
    print('Copy scores:', copy.scores)
Line Notes
def deep_copy(self):Defines method to create a deep copy of the object
new_scores = [score for score in self.scores]Creates a new list copying each element to avoid shared reference
return Profile(self.name, new_scores)Returns new Profile with independent nested list
copy.scores.append(30)Modifies copy's nested list to verify original is unaffected
import java.util.*;
class Profile {
    String name;
    List<Integer> scores;

    Profile(String name, List<Integer> scores) {
        this.name = name;
        this.scores = scores;
    }

    Profile deepCopy() {
        // Deep copy: create new list and copy elements
        List<Integer> newScores = new ArrayList<>();
        for (Integer score : this.scores) {
            newScores.add(score);
        }
        return new Profile(this.name, newScores);
    }

    public static void main(String[] args) {
        List<Integer> scores = new ArrayList<>(Arrays.asList(10, 20));
        Profile original = new Profile("Alice", scores);
        Profile copy = original.deepCopy();
        System.out.println("Original scores: " + original.scores);
        System.out.println("Copy scores: " + copy.scores);
        copy.scores.add(30);
        System.out.println("After modifying copy scores:");
        System.out.println("Original scores: " + original.scores);
        System.out.println("Copy scores: " + copy.scores);
    }
}
Line Notes
Profile deepCopy() {Defines method to create a deep copy of the Profile object
List<Integer> newScores = new ArrayList<>();Creates new list to hold copied elements
newScores.add(score);Copies each element individually to avoid shared references
copy.scores.add(30);Modifies copy's list to verify original is unaffected
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Profile {
public:
    string name;
    vector<int> scores;

    Profile(string n, vector<int> s) : name(n), scores(s) {}

    Profile deepCopy() {
        // Deep copy: vector copy is deep by default
        vector<int> newScores = scores; // copies vector elements
        return Profile(name, newScores);
    }
};

int main() {
    vector<int> scores = {10, 20};
    Profile original("Alice", scores);
    Profile copy = original.deepCopy();
    cout << "Original scores: ";
    for (int x : original.scores) cout << x << " ";
    cout << endl;
    cout << "Copy scores: ";
    for (int x : copy.scores) cout << x << " ";
    cout << endl;
    copy.scores.push_back(30);
    cout << "After modifying copy scores:" << endl;
    cout << "Original scores: ";
    for (int x : original.scores) cout << x << " ";
    cout << endl;
    cout << "Copy scores: ";
    for (int x : copy.scores) cout << x << " ";
    cout << endl;
    return 0;
}
Line Notes
Profile deepCopy() {Defines deep copy method; vector copy is deep by default in C++
vector<int> newScores = scores;Copies vector elements to new vector for independence
copy.scores.push_back(30);Modifies copy's vector to verify original is unaffected
for (int x : original.scores)Prints original scores to confirm no change
class Profile {
    constructor(name, scores) {
        this.name = name;
        this.scores = scores;
    }

    deepCopy() {
        // Deep copy: create new array copying each element
        const newScores = this.scores.slice();
        return new Profile(this.name, newScores);
    }
}

// Driver code
const original = new Profile('Alice', [10, 20]);
const copy = original.deepCopy();
console.log('Original scores:', original.scores);
console.log('Copy scores:', copy.scores);
copy.scores.push(30);
console.log('After modifying copy scores:');
console.log('Original scores:', original.scores);
console.log('Copy scores:', copy.scores);
Line Notes
deepCopy() {Defines deep copy method creating independent nested array
const newScores = this.scores.slice();Copies array elements to new array to avoid shared reference
return new Profile(this.name, newScores);Returns new Profile with independent nested array
copy.scores.push(30);Modifies copy's array to verify original is unaffected
⏱
Complexity
TimeO(n) where n is size of nested collections
SpaceO(n) additional space for new nested objects

Deep copy duplicates nested objects, so time and space scale with nested data size.

💡 For a nested list of size 1000, deep copy creates a new list of 1000 elements, which takes more time and memory.
Interview Verdict: Accepted and recommended for safe cloning of nested objects

This approach is the standard way to avoid bugs from shared references in nested objects.

🧠
Optimal: Using Built-in or Language-Specific Clone/Copy Utilities
💡 Many languages provide built-in utilities or interfaces to perform cloning efficiently and correctly, reducing manual errors and boilerplate.

Intuition

Leverage language features like copy constructors, clone interfaces, or serialization to implement deep copy cleanly and reliably.

Algorithm

  1. Implement or use the language's clone or copy interface.
  2. For deep copy, override clone method to recursively clone nested objects.
  3. Use serialization/deserialization if supported to clone entire object graph.
  4. Return the cloned object.
💡 This approach abstracts away manual copying details and reduces bugs, but requires understanding language-specific features.
</>
Code
import copy

class Profile:
    def __init__(self, name, scores):
        self.name = name
        self.scores = scores

    def __deepcopy__(self, memo):
        # Use copy.deepcopy for nested objects
        new_name = copy.deepcopy(self.name, memo)
        new_scores = copy.deepcopy(self.scores, memo)
        return Profile(new_name, new_scores)

# Driver code
if __name__ == '__main__':
    original = Profile('Alice', [10, 20])
    copy_obj = copy.deepcopy(original)
    print('Original scores:', original.scores)
    print('Copy scores:', copy_obj.scores)
    copy_obj.scores.append(30)
    print('After modifying copy scores:')
    print('Original scores:', original.scores)
    print('Copy scores:', copy_obj.scores)
Line Notes
def __deepcopy__(self, memo):Overrides deepcopy protocol to customize deep copy behavior
new_name = copy.deepcopy(self.name, memo)Deep copies primitive or nested fields safely
new_scores = copy.deepcopy(self.scores, memo)Deep copies nested list to avoid shared references
copy_obj.scores.append(30)Modifies copy's nested list to verify original is unaffected
import java.util.*;
class Profile implements Cloneable {
    String name;
    List<Integer> scores;

    Profile(String name, List<Integer> scores) {
        this.name = name;
        this.scores = scores;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // Deep clone: clone nested list
        List<Integer> newScores = new ArrayList<>(this.scores);
        return new Profile(this.name, newScores);
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        List<Integer> scores = new ArrayList<>(Arrays.asList(10, 20));
        Profile original = new Profile("Alice", scores);
        Profile copy = (Profile) original.clone();
        System.out.println("Original scores: " + original.scores);
        System.out.println("Copy scores: " + copy.scores);
        copy.scores.add(30);
        System.out.println("After modifying copy scores:");
        System.out.println("Original scores: " + original.scores);
        System.out.println("Copy scores: " + copy.scores);
    }
}
Line Notes
class Profile implements Cloneable {Implements Cloneable interface to enable cloning
protected Object clone() throws CloneNotSupportedException {Overrides clone method to customize cloning
List<Integer> newScores = new ArrayList<>(this.scores);Creates new list to deep copy nested collection
Profile copy = (Profile) original.clone();Calls clone method to get deep copied object
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Profile {
public:
    string name;
    vector<int> scores;

    Profile(string n, vector<int> s) : name(n), scores(s) {}

    Profile* clone() {
        // Deep copy: create new Profile with copied vector
        vector<int> newScores = scores;
        return new Profile(name, newScores);
    }
};

int main() {
    vector<int> scores = {10, 20};
    Profile original("Alice", scores);
    Profile* copy = original.clone();
    cout << "Original scores: ";
    for (int x : original.scores) cout << x << " ";
    cout << endl;
    cout << "Copy scores: ";
    for (int x : copy->scores) cout << x << " ";
    cout << endl;
    copy->scores.push_back(30);
    cout << "After modifying copy scores:" << endl;
    cout << "Original scores: ";
    for (int x : original.scores) cout << x << " ";
    cout << endl;
    cout << "Copy scores: ";
    for (int x : copy->scores) cout << x << " ";
    cout << endl;
    delete copy;
    return 0;
}
Line Notes
Profile* clone() {Defines clone method returning pointer to new deep copied object
vector<int> newScores = scores;Copies vector elements to new vector for deep copy
Profile* copy = original.clone();Calls clone to get deep copy
copy->scores.push_back(30);Modifies copy's vector to verify original is unaffected
class Profile {
    constructor(name, scores) {
        this.name = name;
        this.scores = scores;
    }

    clone() {
        // Deep copy using JSON methods (simple but limited)
        const cloneObj = JSON.parse(JSON.stringify(this));
        return new Profile(cloneObj.name, cloneObj.scores);
    }
}

// Driver code
const original = new Profile('Alice', [10, 20]);
const copy = original.clone();
console.log('Original scores:', original.scores);
console.log('Copy scores:', copy.scores);
copy.scores.push(30);
console.log('After modifying copy scores:');
console.log('Original scores:', original.scores);
console.log('Copy scores:', copy.scores);
Line Notes
clone() {Defines clone method using JSON serialization for deep copy
const cloneObj = JSON.parse(JSON.stringify(this));Serializes and deserializes object to create deep copy
return new Profile(cloneObj.name, cloneObj.scores);Returns new Profile instance with copied data
copy.scores.push(30);Modifies copy's array to verify original is unaffected
⏱
Complexity
TimeO(n) where n is size of nested collections
SpaceO(n) additional space for new nested objects

Built-in utilities handle deep copy efficiently and correctly, abstracting complexity.

💡 Using built-in clone methods saves time and reduces bugs compared to manual copying.
Interview Verdict: Accepted and preferred in real-world code for maintainability and correctness

This approach shows mastery of language features and is best practice for cloning.

📊
All Approaches - One-Glance Tradeoffs
💡 In interviews, implement shallow copy first to show understanding, then deep copy manually or with built-in utilities for correctness.
ApproachTimeSpaceStack RiskReconstructUse In Interview
1. Brute Force (Shallow Copy)O(1)O(1)NoN/AMention only - demonstrates basic concept. Note: C++ vector copy is deep, so shallow copy differs.
2. Better (Manual Deep Copy)O(n) nested sizeO(n)Possible if recursion too deepYesCode this to show understanding of deep copy
3. Optimal (Built-in Clone/Serialization)O(n)O(n)Depends on implementationYesMention as best practice in production
💼
Interview Strategy
💡 Use this guide to understand the problem deeply before interviews. Start by clarifying the difference between shallow and deep copy, then explain your approach step-by-step. Practice coding all approaches to be ready for any follow-up questions.

How to Present

Step 1: Clarify the problem and ask if nested objects exist.Step 2: Explain shallow copy and its limitations.Step 3: Implement shallow copy to demonstrate understanding.Step 4: Introduce deep copy and recursive copying of nested objects.Step 5: Show how to use built-in cloning utilities for optimal solution.Step 6: Discuss edge cases and test your code.

Time Allocation

Clarify: 3min → Approach: 5min → Code: 10min → Test: 5min. Total ~23min

What the Interviewer Tests

Interviewer tests your understanding of object references, cloning concepts, and ability to implement safe copying. They also check if you can use language features effectively.

Common Follow-ups

  • How to handle cyclic references in deep copy? → Use memoization or hash maps to track visited objects.
  • Can you implement deep copy for arbitrary objects? → Discuss serialization or reflection-based cloning.
💡 These follow-ups test your deeper understanding of cloning complexities and your ability to handle advanced scenarios.
🔍
Pattern Recognition

When to Use

1. You need to create copies of objects without affecting originals. 2. Objects have nested mutable references. 3. You want to avoid expensive object creation from scratch. 4. You want to clone objects efficiently and safely.

Signature Phrases

clone methoddeep copy vs shallow copyobject copyingprototype pattern

NOT This Pattern When

Factory Pattern - creates new objects but not copies; Builder Pattern - constructs complex objects stepwise.

Similar Problems

Copy Constructor Implementation - similar concept of copying objectsCloneable Interface Usage - language-specific cloningSerialization-based Cloning - alternative deep copy technique

Practice

(1/5)
1. When a new feature is added by extending a class hierarchy following the Open/Closed Principle, what is the typical sequence of events when the system executes a method call on the new subclass instance?
easy
A. The base class method is always executed first, then the subclass method overrides it afterward
B. The system duplicates the base class code inside the subclass to avoid modifying the base
C. The subclass method is invoked directly due to polymorphism, without modifying base class code
D. Both base and subclass methods execute sequentially because the base class is modified to call the subclass

Solution

  1. Step 1: Understand polymorphic dispatch

    Method calls on subclass instances invoke the subclass's overridden method directly.
  2. Step 2: Base class code remains unchanged

    The base class is closed for modification; no changes are made to call subclass methods explicitly.
  3. Step 3: Why other options are incorrect

    The base class method is always executed first, then the subclass method overrides it afterward incorrectly suggests base method runs first then subclass; Both base and subclass methods execute sequentially because the base class is modified to call the subclass implies base class modification; The system duplicates the base class code inside the subclass to avoid modifying the base suggests code duplication, violating DRY and OCP.
  4. Final Answer:

    Option C -> Option C
  5. Quick Check:

    Polymorphism enables extension without modifying base code.
Hint: Polymorphism calls subclass methods directly [OK]
Common Mistakes:
  • Assuming base method always runs first
  • Believing base class must be modified to support extension
  • Thinking code duplication is a valid OCP strategy
2. Why might using an abstract class instead of an interface limit flexibility in a large-scale system design?
medium
A. Because abstract classes do not support polymorphism.
B. Because abstract classes cannot define method signatures without implementation.
C. Because a class can only extend one abstract class but can implement multiple interfaces.
D. Because abstract classes force all methods to be implemented immediately.

Solution

  1. Step 1: Recall inheritance limitations

    Most languages allow single inheritance of classes, limiting abstract class extension to one per class.
  2. Step 2: Interface multiple implementation

    Classes can implement multiple interfaces, allowing flexible contracts from various sources.
  3. Step 3: Why other options are incorrect

    Abstract classes can define abstract methods (method signatures), support polymorphism, and do not force immediate implementation if abstract.
  4. Final Answer:

    Option C -> Option C
  5. Quick Check:

    Single inheritance limits abstract class use; interfaces allow multiple contracts.
Hint: Abstract classes limit inheritance; interfaces allow multiple implementations.
Common Mistakes:
  • Believing abstract classes cannot have abstract methods.
  • Thinking abstract classes do not support polymorphism.
  • Assuming abstract classes force immediate method implementation.
3. Which of the following statements about interfaces and abstract classes is INCORRECT?
medium
A. Interfaces can declare fields that hold state.
B. Abstract classes can have constructors and maintain state.
C. Interfaces can contain default method implementations in some languages.
D. Abstract classes can provide partial method implementations.

Solution

  1. Step 1: Interfaces and state

    Interfaces cannot hold instance fields; they only declare constants (static final fields).
  2. Step 2: Abstract classes and state

    Abstract classes can have constructors and instance variables to maintain state.
  3. Step 3: Default methods in interfaces

    Modern languages allow default method implementations in interfaces.
  4. Step 4: Partial implementation in abstract classes

    Abstract classes can provide some method implementations while leaving others abstract.
  5. Final Answer:

    Option A -> Option A
  6. Quick Check:

    Interfaces cannot hold mutable state; abstract classes can.
Hint: Interfaces declare behavior, abstract classes can hold state and code.
Common Mistakes:
  • Assuming interfaces can have instance variables.
  • Confusing default methods with full implementations.
  • Believing abstract classes cannot have constructors.
4. Which of the following is a common trade-off or limitation when strictly applying the Open/Closed Principle in a large software system?
medium
A. It forces all changes to be made in a single base class, increasing risk of bugs
B. It can lead to excessive class proliferation, making the codebase harder to navigate
C. It eliminates the need for interfaces or abstract classes, simplifying design
D. It guarantees zero runtime overhead due to polymorphism

Solution

  1. Step 1: Identify trade-offs of OCP

    Strict adherence often results in many small subclasses, increasing complexity.
  2. Step 2: Why other options are false

    It forces all changes to be made in a single base class, increasing risk of bugs is opposite to OCP's goal; changes are made via extension, not base modification. It eliminates the need for interfaces or abstract classes, simplifying design is false because OCP relies on abstractions like interfaces. It guarantees zero runtime overhead due to polymorphism is incorrect; polymorphism can introduce slight runtime overhead.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Class explosion is a known practical downside of OCP.
Hint: OCP can cause many small classes [OK]
Common Mistakes:
  • Thinking OCP centralizes changes in base classes
  • Believing OCP removes need for abstractions
  • Assuming polymorphism has no runtime cost
5. In a legacy system, a class handles both business logic and logging. You want to refactor it following SRP, but the logging code is tightly intertwined with business logic. What is the best approach to refactor this while respecting SRP?
hard
A. Ignore SRP in this case because legacy code should not be refactored.
B. Leave logging inside the class because extracting it would break existing functionality and increase risk.
C. Merge business logic and logging into a utility class to centralize all cross-cutting concerns.
D. Extract logging into a separate class and replace logging calls with calls to this new class, even if it requires modifying many places.

Solution

  1. Step 1: Identify responsibilities

    Business logic and logging are separate reasons to change.
  2. Step 2: Refactor strategy

    Extract logging into its own class to isolate changes related to logging.
  3. Step 3: Address tight coupling

    Though intertwined, refactoring calls to the new logging class improves maintainability and respects SRP.
  4. Step 4: Evaluate other options

    Options B and D avoid refactoring, risking future issues; C increases coupling by merging unrelated concerns.
  5. Final Answer:

    Option D -> Option D
  6. Quick Check:

    Extract and isolate responsibilities even if it requires effort -> SRP compliance.
Hint: Separate concerns even if intertwined; refactor stepwise.
Common Mistakes:
  • Avoiding refactoring due to perceived risk.
  • Merging unrelated concerns for convenience.
  • Ignoring SRP in legacy code.
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