Jump into concepts and practice - no test required
or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
▶
Steps
setup
Define Product Class: House
The House class is defined to represent the complex object being built. It contains a list of parts and methods to add parts and display the house composition.
💡 Defining the product class is essential because it represents the final object that the builder will construct step-by-step.
💡 The product class holds the components that will be assembled by the builder.
setup
Define Builder Interface: HouseBuilder
The HouseBuilder class is defined as the builder interface specifying methods to build parts of the House. It initializes a House instance to assemble.
💡 The builder interface abstracts the construction steps, allowing different builders to implement them differently.
Factory vs Abstract Factory vs Builder - When to Use Each - Watch the Algorithm Execute, Step by Step
Watching each step reveals how the Builder pattern separates construction from representation, making complex object creation manageable and flexible.
Step 1/11
·Active fill★Answer cell
Defines the product class that will be built stepwise.
House
−parts: List[str]
+__init__()
+add()
+__str__()
Builder interface holds and constructs the product.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
+__init__()
+build_walls()
+build_roof()
+2 more
HouseBuilder ◆ House (1:1)
Builder method adds a specific part to the product.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
+build_walls()
HouseBuilder ◆ House (1:1)
Builder method adds another specific part to the product.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
+build_roof()
HouseBuilder ◆ House (1:1)
Builder method adds an optional part to the product.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
+build_pool()
HouseBuilder ◆ House (1:1)
Builder exposes the final product after construction.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
+get_result()
HouseBuilder ◆ House (1:1)
Director controls the building process using a builder.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
+build_walls()
+build_roof()
+build_pool()
+1 more
Director
−builder: HouseBuilder
+__init__()
+construct_basic_house()
+construct_luxury_house()
HouseBuilder ◆ House (1:1)Director ◇ HouseBuilder (1:1)
Director sequences builder calls to create a basic product.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
+build_walls()
+build_roof()
Director
−builder: HouseBuilder
+construct_basic_house()
HouseBuilder ◆ House (1:1)Director ◇ HouseBuilder (1:1)
Director sequences builder calls to create a luxury product.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
+build_walls()
+build_roof()
+build_pool()
Director
−builder: HouseBuilder
+construct_luxury_house()
HouseBuilder ◆ House (1:1)Director ◇ HouseBuilder (1:1)
Client retrieves the constructed product from the builder.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
+get_result()
Director
−builder: HouseBuilder
HouseBuilder ◆ House (1:1)Director ◇ HouseBuilder (1:1)
Product displays its assembled parts confirming construction.
House
−parts: List[str]
+__init__()
+add()
+__str__()
HouseBuilder
−house: House
Director
−builder: HouseBuilder
HouseBuilder ◆ House (1:1)Director ◇ HouseBuilder (1:1)
Key Takeaways
✓ Builder pattern separates complex object construction from its representation.
This separation is hard to grasp from code alone but becomes clear when watching stepwise construction.
✓ Director controls the construction sequence, enabling different product variants.
Seeing the director call different builder methods clarifies how product complexity and customization are managed.
✓ Builder methods modularly add parts, allowing optional features to be included flexibly.
Watching each part addition step reveals how optional components like pools are integrated without changing the product class.
Practice
(1/5)
1. You are designing a system where multiple unrelated classes must guarantee implementation of certain methods but share no common code. Which abstraction mechanism is most appropriate to enforce this contract?
easy
A. Use an abstract class to define the methods and provide partial implementation.
B. Use an abstract class only if all classes share a common ancestor.
C. Use a concrete class and rely on inheritance for code reuse.
D. Use an interface to declare the methods without any implementation.
Solution
Step 1: Identify the need for a contract without shared code
Interfaces define method signatures without implementation, perfect for unrelated classes needing a common contract.
Step 2: Why abstract classes are less suitable here
Abstract classes provide partial implementation and require a common ancestor, which unrelated classes lack.
Step 3: Why concrete classes and inheritance don't fit
Concrete classes imply implementation and inheritance assumes a hierarchy, which is not guaranteed.
Final Answer:
Option D -> Option D
Quick Check:
Interfaces enforce contracts without imposing inheritance or shared code.
Hint: Use interfaces when only a contract is needed, abstract classes when sharing code.
Common Mistakes:
Assuming abstract classes are always better for abstraction.
Confusing contract enforcement with code reuse.
Believing unrelated classes can share an abstract class.
2. When a class inherits from multiple classes that have a method with the same name, describe the step-by-step process the Method Resolution Order (MRO) uses to determine which method is called.
easy
A. MRO uses a linearization algorithm that merges the order of parents and their ancestors to find the method.
B. MRO searches the first parent class fully before moving to the next parent class.
C. MRO always calls the method from the last parent class listed in the inheritance.
D. MRO randomly picks the method from any parent class that defines it.
Solution
Step 1: Understand naive search
MRO does not simply search the first parent class fully before moving to the next; it uses a more sophisticated approach.
Step 2: Recognize MRO linearization
MRO uses a specific linearization (like C3 linearization) that merges parent classes and their ancestors in a consistent order.
Step 3: Eliminate incorrect options
MRO always calls the method from the last parent class listed in the inheritance is incorrect because the last parent is not always chosen; order and ancestors matter. MRO randomly picks the method from any parent class that defines it is incorrect because MRO is deterministic, not random.
Final Answer:
Option A -> Option A
Quick Check:
MRO merges inheritance hierarchies to find the correct method in a predictable order.
Hint: MRO = deterministic linearization of inheritance graph
Common Mistakes:
Assuming simple left-to-right search suffices
Believing last parent always overrides
Thinking method choice is random
3. What is a common trade-off or limitation when strictly applying the Single Responsibility Principle in a large system?
medium
A. It forces all classes to be tightly coupled to maintain cohesion.
B. It always reduces code complexity and never increases the number of classes.
C. It can lead to a proliferation of small classes, increasing the complexity of navigation and understanding.
D. It eliminates the need for interfaces or abstractions in the system.
Solution
Step 1: Understand SRP effect
SRP encourages splitting responsibilities, which can increase the number of classes.
Step 2: Trade-off analysis
More classes improve modularity but can make the system harder to navigate and understand due to fragmentation.
Step 3: Evaluate other options
It always reduces code complexity and never increases the number of classes. is false because SRP can increase class count; It forces all classes to be tightly coupled to maintain cohesion. is false because SRP reduces coupling; It eliminates the need for interfaces or abstractions in the system. is false because SRP does not remove the need for abstractions.
Final Answer:
Option C -> Option C
Quick Check:
More classes can complicate system navigation -> trade-off of SRP.
Hint: SRP trades fewer responsibilities for more classes.
Common Mistakes:
Believing SRP always simplifies codebase size.
Confusing coupling with cohesion effects.
Assuming SRP removes need for design patterns.
4. If a class exposes a public getter but no setter for a private field, what is a likely reason an interviewer would probe this design choice?
hard
A. To test if the candidate thinks public fields are better than getters
B. To confirm that the candidate knows getters always require setters
C. To verify that the candidate believes private fields should never be exposed
D. To check if the candidate understands immutability and controlled read-only access
Solution
Step 1: Understand getter-only design
Getter without setter implies read-only access, often for immutability or controlled exposure.
Step 2: Analyze interviewer intent
Interviewer probes if candidate recognizes design for immutability or encapsulation control.
Step 3: Evaluate incorrect options
To confirm that the candidate knows getters always require setters is false; setters are not always required. To verify that the candidate believes private fields should never be exposed is extreme; exposing read-only data is common. To test if the candidate thinks public fields are better than getters is a misconception favoring public fields.
Final Answer:
Option D -> Option D
Quick Check:
Getter-only design supports immutability and controlled access.
Hint: Getter-only means read-only, not incomplete encapsulation [OK]
Common Mistakes:
Assuming getters must have setters
Thinking private fields must never be exposed
Believing public fields are simpler and better
5. If the Composite pattern iterator is extended to allow reusing leaf components multiple times during traversal (e.g., shared leaves), which modification is necessary to ensure correct iteration without infinite loops?
hard
A. No change needed; the existing iterator handles reuse naturally.
B. Modify the iterator to push children in original order instead of reversed order.
C. Add a visited set to track and skip already visited components during iteration.
D. Convert the iterator to a recursive traversal to handle reuse correctly.
Solution
Step 1: Understand reuse implications
Reusing leaves means the same component can appear multiple times, risking infinite loops.
Step 2: Identify solution to prevent infinite loops
Tracking visited components prevents revisiting the same node repeatedly during iteration.
Final Answer:
Option C -> Option C
Quick Check:
Visited set avoids infinite loops with shared components [OK]
Hint: Track visited nodes to handle shared components safely [OK]