Welcome to the building's first floor. In module 1 we laid the foundations: you know what a pattern is, which principles it embodies, and how to weigh its cost. Now it is time for the first family of the GoF catalog, the one that governs the birth of objects. It may sound like a minor topic — what could possibly go wrong with a new? — but you will see that Java's most innocent-looking statement is, in fact, the most rigid coupling point of an entire system. This lesson presents the common problem that the five creational patterns solve, gives you the map of the family, and teaches you to recognize in PideYa's code the symptoms that one of them is missing. We will not develop any pattern yet: that starts in the next lesson.
Contents
- The problem:
newis a contract for life - Why creating objects is a responsibility in its own right
- Overview of the five creational patterns
- Symptoms in PideYa: how you can tell a creational pattern is missing
- Class scope vs. object scope in the creational family
- Conclusion
The problem: new is a contract for life
Let's start with a real fragment from PideYa's checkout, as it might have been written in the project's first week:
public class CheckoutService {
public void confirmOrder(Cart cart) {
// Charge the customer
StripeGateway gateway = new StripeGateway("sk_live_pideya_2026");
gateway.charge(cart.getTotal(), cart.getCustomer().getCard());
// Notify the customer
PushNotifier notifier = new PushNotifier();
notifier.send(cart.getCustomer(), "Order confirmed!");
}
}It works. And yet each of those new calls is a decision hard-wired into the code that ties CheckoutService down in three ways:
- It ties it to a concrete class.
CheckoutServicedoes not depend on "a payment gateway" but on Stripe in particular. If the business signs with Redsys tomorrow, this class has to be opened and edited. It is exactly the DIP violation we saw in the principles lesson: a high-level module depending on a detail. - It ties it to the construction process.
CheckoutServiceknows that the gateway needs a secret key, and has it embedded. Any change in how the gateway is built (more parameters, per-environment configuration) propagates changes all the way up here. - It closes the door on extension. Adding a new notification channel or a new gateway forces you to modify code that already worked: an OCP violation. And in tests, there is no way to replace the real gateway with a double: every checkout test would try to charge for real.
The GoF's first maxim — "program to interfaces, not implementations" — has fine print we can now read: even if all your code uses interfaces (PaymentGateway, Notifier), somewhere, someone has to write the new for the concrete class. Interfaces cannot be instantiated. The creational patterns answer precisely the question that fine print leaves open:
Where, how, and who decides which concrete class gets instantiated, so that the rest of the system does not have to know?
Why creating objects is a responsibility in its own right
The central idea of the whole family can be summed up like this: creating an object is a responsibility, and like every responsibility (SRP), it sometimes deserves its own class or its own method. Creational patterns encapsulate two kinds of knowledge so they do not spread across the system:
- What gets created: which concrete class is instantiated (
StripeGatewayorRedsysGateway?PushNotifierorSmsNotifier?). - How it gets created: which steps, parameters, validations, or collaborating objects are needed to leave the instance ready to use.
When that knowledge is encapsulated, client code works only against interfaces and the system gains the property we have been chasing since module 1: the real axes of change (new gateway, new country, new channel) are absorbed by adding pieces, not by modifying existing ones.
An important nuance worth fixing in your mind right away: creational patterns do not eliminate the new, they relocate it. The new StripeGateway(...) will still exist, but it will live in a single place designed for it (a factory, a builder, a creation method), instead of being scattered across twenty business classes.
Overview of the five creational patterns
The GoF catalogs five creational patterns. Here is the family map, one line per pattern; each will get its full lesson in this module:
| Pattern | The idea in one line | Lesson |
|---|---|---|
| Singleton | Guarantee that a class has a single instance and provide a global access point to it | 02-02 |
| Factory Method | Delegate to subclasses the decision of which concrete class to instantiate, behind a creation method | 02-03 |
| Abstract Factory | Create families of related objects (which must be combined with one another) without naming their concrete classes | 02-04 |
| Builder | Build complex objects step by step, separating construction from the final representation | 02-05 |
| Prototype | Create new objects by cloning an existing instance instead of instantiating a class | 02-06 |
Notice that each pattern attacks a different edge of the same problem:
- Singleton controls how many instances exist.
- Factory Method and Abstract Factory control which concrete class gets chosen (one for a single product, the other for whole families).
- Builder controls the process of construction when it is long or has variants.
- Prototype controls the source: the new object is not born from a class but from another object.
In the module's final comparison we will pit them against each other and you will see how they combine; for now this map is enough.
Symptoms in PideYa: how you can tell a creational pattern is missing
As we learned in the lesson on the scale, patterns are earned, not planted: you reach for them when the code hurts. These are the concrete pains — all real in the growth of a platform like PideYa — that point toward this family. Keep them as a diagnostic checklist; the following lessons will resolve them one by one:
newcalls to concrete classes scattered through business code. Searching fornew StripeGatewayreturns twelve results in seven classes. Switching providers becomes open-heart surgery. → The knowledge of what to create is asking to be centralized (Factory Method).- A
switchorifchain over a "type" that decides what to instantiate, duplicated wherever the object is needed:
// This block appears, with variations, in three different PideYa services
Notifier n;
switch (preferredChannel) {
case PUSH: n = new PushNotifier(); break;
case SMS: n = new SmsNotifier(twilioKey); break;
case EMAIL: n = new EmailNotifier(smtpServer); break;
default: throw new IllegalArgumentException(preferredChannel.toString());
}Every new channel forces you to hunt down and edit every copy. → Centralize the decision (Factory Method).
- Objects that must be mutually consistent, and nothing guarantees it. When PideYa launched in Mexico, an oversight combined the Mexican gateway with the Spanish VAT calculator: miscalculated charges in production. The pieces were created independently and nothing prevented mixing families. → Create the whole family at once (Abstract Factory).
- Telescoping constructors. The
Orderconstructor has grown fatter every sprint until it became unreadable and impossible to call without checking the signature:
Order o = new Order(customer, lines, address, null, null, "no onions",
true, null, TimeSlot.LUNCH, false);
// What is each null? What does the true mean? Nobody knows without reading the signature.→ Step-by-step, readable, validated construction (Builder).
- Creating an object "almost identical" to an existing one means rebuilding it from scratch. The app's "repeat my last order" feature copies the previous order field by field, and every time
Ordergains an attribute somebody forgets to copy it. → Clone instead of rebuilding (Prototype). - Home-grown global state. The platform configuration (commission rates, delivery radii) gets loaded from disk three times because each service makes its own copy, and in production two copies drifted out of sync. → Control uniqueness (Singleton... with the warnings we will see).
- Tests that cannot isolate the subject. Testing
CheckoutServicerequires network access, real keys, and patience, because its collaborators are instantiated inside withnewand there is no way to slip in a test double.
If you recognize several of these symptoms in a codebase, you have a problem you can name without citing any pattern (the first filter from the previous lesson): object creation has become a real, aching axis of change. That is the moment — and not before — to open the creational catalog.
Class scope vs. object scope in the creational family
In the catalog classification we saw that the GoF crosses purpose (creational, structural, behavioral) with scope: whether the pattern fixes its solution through inheritance (class scope, decided at compile time) or through composition and delegation (object scope, configurable at runtime). Among the creational patterns the split is very lopsided:
| Scope | Patterns | Variation mechanism |
|---|---|---|
| Class | Factory Method | Variation happens by inheriting: each subclass of the creator overrides which product it instantiates. The choice is fixed by the subclass you use. |
| Object | Abstract Factory, Builder, Prototype, Singleton | Variation happens by composing: the client receives (or locates) an object — a factory, a builder, a prototype — and it can be swapped for another at runtime. |
This asymmetry is no accident: it reflects the GoF's second maxim, "favor composition over inheritance". Four of the five creational patterns delegate creation to an object that can be injected, replaced, or configured without recompiling; only Factory Method relies on inheritance, and even so we will see in its lesson modern variants (lambdas, generics) that push it toward composition too. As you study each pattern, always ask yourself which scope it belongs to: it will tell you when the concrete class is decided (at compile time or at runtime) and, therefore, how much flexibility you are buying and at what price.
Common Mistakes and Tips
- Believing the goal is to "ban
new". No: the goal is for thenewof each concrete class to live in a single place with a proper name. A localnew ArrayList<>(), or thenewof a simple value object likeMoney, needs no pattern at all. - Starting the design by choosing the pattern. The correct order is symptom → problem → pattern. If PideYa's checkout had had a single, stable gateway for years, the direct
newcalls would be perfectly defensible (YAGNI). - Confusing the patterns with each other before studying them. It is normal for Factory Method and Abstract Factory to sound identical right now; do not try to tell them apart from memory yet. The coming lessons separate them with examples, and the comparison will put them face to face.
- Forgetting tests as a symptom. "I cannot test this class without spinning up half the system" is one of the most reliable indicators that creation is in the wrong place. Listen to your tests: they are your design's first client.
Exercises
Exercise 1: hunting the couplings
In this fragment from PideYa's restaurant onboarding service, identify every point where the code is coupled to a concrete class or to a construction process, and classify each one under the symptom from section 4 that best describes it:
public class RestaurantOnboardingService {
public void register(RestaurantData data) {
CifValidator validator = new CifValidator();
if (!validator.validate(data.getCif())) throw new InvalidCifException();
Restaurant r = new Restaurant(data.getName(), data.getCif(),
data.getAddress(), null, null, true, false, null, 30, null);
EmailNotifier email = new EmailNotifier("smtp.pideya.com", 587, "[email protected]");
email.send(data.getContactEmail(), "Welcome to PideYa");
}
}Exercise 2: matching a pattern to each symptom
Without implementing anything (you do not know how yet), indicate which creational pattern from the section 3 overview seems to fit each PideYa situation, and justify it in one sentence:
- The app lets you "duplicate" an entire restaurant menu to create the night-shift menu with small changes.
- Freelance couriers and in-house fleet couriers require different contract, insurance, and settlement objects, which must always belong to the same regime as one another.
- The
Invoiceobject has 4 required fields and 9 optional ones, and its constructor is unmanageable. - The connection to the messaging broker must be a single one for the whole process and reachable from several services.
- The notification service must create the right notifier (push, SMS, email) according to the customer's preference, and today it does so with a
switchrepeated across three classes.
Exercise 3: pattern or YAGNI?
PideYa generates an order identifier with new OrderIdGenerator().next(). The generator has no configuration state, there is a single implementation, and there are no plans to change it. A teammate proposes "preparing it for the future" with a factory. Apply the filters from lesson 01-06 and give your verdict.
Solutions
Solution 1:
new CifValidator(): dependency on a concrete class inside business code; it prevents substituting a double in tests (symptoms "tests that cannot isolate the subject" and "scatterednewcalls").new Restaurant(...)with ten arguments, severalnulls, and unnamed literals (true, false, 30): a textbook telescoping constructor (symptom → Builder).new EmailNotifier("smtp...", 587, ...): double coupling, to the concrete class (what if the customer prefers SMS?) and to the construction process (host and port hard-wired here, which is the worst possible place for them). Symptoms: "scatterednewcalls" and construction knowledge spread around (→ Factory Method).
Solution 2:
- Prototype: the new object is born by cloning an existing menu, not by rebuilding it from zero.
- Abstract Factory: contract + insurance + settlement form a family that must stay consistent (all freelance-regime or all fleet-regime).
- Builder: step-by-step construction with required and optional parts, validating at the end.
- Singleton (with the reservations we will see in the next lesson): instance uniqueness and shared access.
- Factory Method: centralize in a creation method the decision of which concrete notifier to instantiate.
Solution 3: it fails filter 2 (the axis of change is speculative: a single implementation, no plans) and filter 3 (the simple code does not hurt: the generator has no dependencies that complicate tests). Verdict: do not introduce a factory; at most, if OrderIdGenerator is used in classes that want deterministic tests, inject it as a collaborator (basic DIP) with no extra pattern. The factory will earn its place the day a second real way of generating identifiers exists.
Conclusion
You now have the map of the creational family: the common enemy is the coupling that every new hard-wires between business code and concrete classes (with OCP and DIP as the wounded principles), and the five patterns are five ways of encapsulating creation — controlling how many instances exist, which class gets chosen, how it is built, or which object it is cloned from. You also know how to read the symptoms that justify opening them and which scope (class or object) each one plays in.
We start the parade with the most famous pattern, the shortest to write... and the most controversial in the whole catalog: guaranteeing that something exists only once is easy; doing it without creating a bigger problem, not so much. See you in Singleton.
Software Design Patterns Course
Module 1: Introduction to Design Patterns
- What Are Design Patterns?
- History and Origin of Design Patterns
- Design Principles: SOLID and Other Foundations
- Essential UML for Understanding Patterns
- Classification of Design Patterns
- Advantages and Disadvantages of Using Design Patterns
Module 2: Creational Patterns
- Introduction to Creational Patterns
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
- Comparing and Choosing Creational Patterns
Module 3: Structural Patterns
- Introduction to Structural Patterns
- Adapter
- Bridge
- Composite
- Decorator
- Facade
- Flyweight
- Proxy
- Comparing and Choosing Structural Patterns
Module 4: Behavioral Patterns
- Introduction to Behavioral Patterns
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
- Comparing and Choosing Behavioral Patterns
Module 5: Applying Design Patterns
- How to Select the Right Pattern
- Practical Examples of Pattern Usage
- Design Patterns in Real Projects
- Refactoring with Design Patterns
- Anti-Patterns: When Patterns Become a Problem
Module 6: Advanced Design Patterns
- Design Patterns in Modern Architectures
- Design Patterns in Microservices
- Design Patterns in Distributed Systems
- Concurrency Patterns
- Design Patterns in Agile Development
