Creation pain
If building objects is becoming conditional, repetitive, or configuration-heavy, the creational family is usually the first place to look.
Developers usually struggle with patterns not because the patterns are complicated, but because the choice feels ambiguous. This page is about turning pattern selection into a force-based decision: what kind of variation is growing, what kind of coupling is hurting, and what kind of creation or behavior is becoming too awkward?
In Java commerce flows, one problem might be gateway creation, another might be optional behavior layering, and another might be state-driven workflow logic. The right pattern is clearer when the force is named clearly.
The fastest way to choose patterns well is to stop asking “which pattern should I use?” in the abstract. Ask instead: what is the pressure? Is object creation full of branching? Is behavior changing by runtime condition? Are clients depending on shapes they should not need to know?
Pattern choice also improves when you compare near neighbors. Factory Method, Abstract Factory, and Builder solve related but different creation problems. Strategy, State, and Command can all look like “behavior moved into objects,” but the reasons they exist are different.
Good pattern choice is less about catalog recall and more about distinguishing forces precisely enough that one response becomes a better fit than the others.
If building objects is becoming conditional, repetitive, or configuration-heavy, the creational family is usually the first place to look.
If interfaces do not align or wrappers are proliferating, structural patterns are often relevant.
If behavior varies by state, request type, or collaborator chain, behavioral patterns are usually the stronger lens.
package org.javaomnibus.ecommerce.gof;
public final class CheckoutContext {
public PaymentGateway gatewayFor(Order order) {
if ("CARD".equals(order.paymentMethod())) {
return new CardGateway();
}
if ("WALLET".equals(order.paymentMethod())) {
return new WalletGateway();
}
throw new IllegalArgumentException("Unsupported method");
}
public Money applyDiscount(Order order) {
if (order.isPremiumCustomer()) {
return order.total().multiply(95).divide(100);
}
return order.total();
}
}
Forcing every design pressure into a named pattern can create unnecessary abstraction. Some problems are still better solved by straightforward refactoring without a formal pattern structure.