Design Patterns in the JDK
Where the classic GoF patterns actually live in the Java standard library, and the Java-specific idioms and pitfalls of implementing each one. Naming real JDK examples is what separates a memorized pattern catalog from working knowledge in an interview.
part ofJavaoverview, primer and where to startread it →on this pageshowhide
explore
- Singleton in Java4 questions
- Factory Method in Java5 questions
- Abstract Factory in Java5 questions
- Builder in Java5 questions
- Prototype in Java4 questions
- Adapter in Java5 questions
- Decorator in Java5 questions
- Proxy in Java4 questions
- Facade in Java4 questions
- Composite in Java5 questions
- Bridge in Java5 questions
- Flyweight in Java5 questions
- Observer in Java5 questions
- Strategy in Java4 questions
- Template Method in Java5 questions
- Iterator in Java5 questions
- Command in Java5 questions
- State in Java5 questions
- Chain of Responsibility in Java5 questions
- Visitor in Java5 questions
- Mediator in Java5 questions
- Memento in Java5 questions
questions
105 · 22 sectionsWhat is the Singleton pattern, and what are the common ways to implement it in Java?
basics
~20 sA Singleton ensures a class has exactly one instance and gives global access to it. In Java you hide the constructor (make it private) and expose one shared instance, either created eagerly in a static field or lazily in a getInstance() method.
Explain thread-safe lazy initialization in Java: why is double-checked locking broken without volatile, and how do you fix it?
basics
~20 sIf two threads create a lazy singleton at the same time you can get two instances. Double-checked locking checks the field, locks only if it is null, then checks again. Without the volatile keyword on the field, another thread can see a half-built object, so you must mark the field volatile.
How can a class-based Java singleton's single-instance guarantee be broken, and how do you defend against each attack?
basics
~20 sEven with a private constructor, reflection can call it, deserialization can build a second object, and clone() can copy it. Defend by throwing from the constructor if an instance exists, adding readResolve() to return the existing instance, and refusing to clone. Or just use an enum singleton, which blocks all of these.
When is a Singleton the right choice in Java, and what alternatives (like dependency injection) should you prefer?
basics
~20 sUse a true Singleton only when there genuinely must be one instance, like a registry or a hardware accessor. For most shared services, create one instance and pass it where needed (dependency injection) instead, because hard-coded singletons are global state and hard to test.
What is the Factory Method pattern, and how does it differ from calling a constructor directly?
basics
~20 sFactory Method means asking a method to make an object instead of using new yourself. The method decides which concrete class to build and returns it, usually typed as an interface or parent class, so the caller doesn't depend on the exact type.
Explain how `Calendar.getInstance()` and `NumberFormat.getInstance()` illustrate Factory Method in the JDK. What do they return and why is that returned type not fixed?
basics
~20 sBoth are static getInstance() factories. They don't return a fixed class — they look at your locale/region and pick the right concrete subclass (e.g. a Gregorian calendar, or a locale-specific number format) and hand it back typed as the abstract base. You get a ready, region-appropriate object without naming the concrete class.
How do interfaces plus implementing classes realize the 'deferred instantiation' intent of Factory Method, and how does this support open/closed extension of an API over time?
basics
~20 sAn interface says what an object does; classes implement it. A factory method returns the interface, so the caller only knows the interface. The factory can pick or add new implementing classes later without changing callers. That's deferred instantiation: the 'which class' decision is postponed and isolated inside the factory.
Distinguish the GoF Factory Method pattern from a simple static factory method in Java. When is each appropriate?
basics
~20 sA static factory is just a named static method that returns an object (like List.of). The GoF Factory Method is a pattern: a creator class has an overridable method that subclasses override to choose which product to build. Static factory = convenience; GoF = a hierarchy where subclasses decide the product.
What are the practical drawbacks and design trade-offs of leaning heavily on factory methods (static factories and the GoF pattern) in a large Java codebase?
basics
~20 sFactories hide the concrete type, which is great for decoupling but costs discoverability and adds indirection. A static factory method can't be subclassed if the class has no public/protected constructor, factories aren't as obvious as new, and a creator hierarchy can explode into many subclasses. Use them where variation is real, not everywhere.
How does Abstract Factory differ from Factory Method in Java API design, with JDK examples of each?
basics
~10 sFactory Method is one method that creates one product (e.g. Calendar.getInstance()). Abstract Factory is an object with several creation methods that build a whole family of related products together (e.g. DocumentBuilderFactory).
What is the Abstract Factory pattern, and how does the JDK's DocumentBuilderFactory illustrate it?
basics
~20 sAbstract Factory is a creational pattern: an object whose job is to create a family of related objects without you naming their concrete classes. DocumentBuilderFactory.newInstance() gives you a factory that builds matching XML parser objects.
Sketch a small Abstract Factory in Java for a family of related products. What are the participants and why is the client decoupled?
basics
~20 sDefine abstract product interfaces, an abstract factory interface with a create method per product, and concrete factories that return one matching set of products. The client holds the abstract factory and calls its methods, never using new on concretes.
JAXP factories like DocumentBuilderFactory are Abstract Factories whose provider is pluggable. How does the runtime select the implementation, and what design forces does that pluggability serve?
basics
~20 snewInstance() searches an ordered list — a system property, a jaxp.properties file, the service-loader (META-INF/services), then the built-in default — and uses the first provider it finds. This lets you swap XML libraries without changing code.
As an architect, when is Abstract Factory the right choice in modern Java, and when is it over-engineering relative to DI, Factory Method, or a plain constructor?
basics
~20 sUse Abstract Factory when you need several related objects that must come from the same consistent variant and that variant must be swappable. If you only need one object, or a DI container already wires implementations, a simpler factory or plain constructor is usually better.
What is the Builder pattern in Java, and what problem does it solve?
basics
~20 sBuilder is a way to construct an object step by step using chained method calls, then a final build() call. It avoids constructors with lots of confusing parameters, and the result is usually an immutable object.
How do you use a Builder to produce an immutable object, and what role does the build() method play?
basics
~10 sThe builder collects values in its own mutable fields, then build() passes them to the target's private constructor, which stores them in final fields. After build() returns, the object can't be changed.
Give examples of the Builder pattern in the JDK and explain how each realizes the pattern.
basics
~10 sStringBuilder, Stream.Builder, and Locale.Builder are JDK examples. Each lets you add values with chained calls and then produces a final object — toString() for StringBuilder, build() for the other two.
How do you write a generic builder with a recursive self-type so it works correctly across an inheritance hierarchy?
basics
~20 sYou make the base builder generic in its own subtype: abstract class Builder<T extends Builder<T>>, have each fluent method return that type T via an abstract self() method overridden by subclasses to return this. This lets a subclass keep chaining the parent's methods without losing its own type.
When should you choose a Builder over constructors, static factories, or records — and when is it the wrong tool?
basics
~20 sUse a Builder when a class has many parameters, especially optional ones, and you want readable construction and an immutable result. For just a few parameters, a constructor, static factory, or a record is simpler and a Builder is needless boilerplate.
What is the difference between a shallow and a deep copy when cloning in Java, and how do you implement a deep clone?
basics
~20 sA shallow copy duplicates the object's fields but shares the objects those fields point to. A deep copy also duplicates the referenced objects so the copy is fully independent. Object.clone() gives a shallow copy; you must add deep copying yourself.
What is the Prototype design pattern, and how is it expressed in Java with Object.clone() and Cloneable?
basics
~10 sPrototype creates new objects by copying an existing instance instead of building one from scratch. In Java you implement Cloneable and override clone() to return a copy of the object.
What are the flaws of Java's Cloneable/clone() mechanism, and why do Effective Java and many teams avoid it?
basics
~20 sCloneable is a marker interface that doesn't contain clone(); clone() lives on Object, is protected, and copies shallowly while bypassing constructors. This makes correct cloning fragile, so Effective Java recommends copy constructors or copy factories instead.
Where does the Prototype idea appear in the JDK, and how would you decide between Prototype/clone, a copy constructor, and a factory in a real design?
basics
~20 sJava's array clone() and types like ArrayList.clone() show the Prototype idea of copying. To choose, prefer copy constructors/factories for normal objects, use array clone() for arrays, and reach for true Prototype when you must copy objects whose concrete type you don't know at compile time.
What is the Adapter pattern, and how does it appear in the JDK?
basics
~20 sAdapter is a wrapper that lets two incompatible interfaces work together. It takes an object with one interface and exposes it as another. In the JDK, InputStreamReader adapts a byte InputStream into a char Reader.
How does Arrays.asList illustrate the Adapter pattern, and what surprising behaviors come from its view semantics?
basics
~20 sArrays.asList wraps an array in the List interface without copying it. The list is a fixed-size view backed by the array: changing the list changes the array and vice versa, set works, but add and remove throw UnsupportedOperationException.
What is the difference between an object adapter and a class adapter in Java, and which does Java favor?
basics
~20 sAn object adapter holds the adaptee as a field and delegates to it (composition). A class adapter extends the adaptee and implements the target (inheritance). Java favors the object adapter because Java allows only single class inheritance.
How do Adapter, Decorator, Proxy, and Facade differ, and how does InputStreamReader vs BufferedReader illustrate the Adapter/Decorator distinction?
basics
~20 sAll four wrap an object, but for different reasons. Adapter changes the interface; Decorator keeps the interface and adds behavior; Proxy keeps the interface and controls access; Facade hides a subsystem behind a simpler interface. InputStreamReader is an Adapter (bytes to chars); BufferedReader is a Decorator (still a Reader, adds buffering).
When should you introduce an Adapter at a module or system boundary rather than changing the interface directly, and what are the design trade-offs?
basics
~20 sUse an Adapter when you can't or shouldn't change either side — third-party libraries, legacy code, or stable public APIs — to keep your code depending on your own clean interface instead of the foreign one. The cost is an extra layer to maintain and translate.
What is the Decorator pattern, and where does the JDK use it (give the canonical example)?
basics
~20 sDecorator wraps an object to add behavior without changing its class. It implements the same type as what it wraps and forwards calls to it, adding extra work. The classic JDK example is java.io: BufferedInputStream wraps an InputStream to add buffering.
When you stack java.io stream decorators, why does the order of wrapping matter? Give an example where wrong order causes a bug or poor performance.
basics
~20 sEach wrapper feeds bytes through the one it wraps, so order decides what happens in what sequence. Put buffering closest to the raw source. If you wrap in the wrong order, you can lose the buffer's benefit (slow) or transform bytes at the wrong stage.
Write a custom Decorator over an existing interface (e.g. a List or an InputStream) that adds behavior, and explain the delegation mechanics.
basics
~20 sImplement the same interface as the thing you wrap, store a reference to it, and forward each method to that reference, adding your extra behavior in the methods you care about. For example, a List wrapper that counts how many times add() is called before delegating to the real list.
How does Decorator differ from Proxy and Adapter? Use JDK examples to distinguish them.
basics
~20 sAll three wrap an object, but with different intent. Decorator adds behavior and keeps the same interface (BufferedInputStream over InputStream). Adapter changes the interface to a different one (Arrays.asList: array to List). Proxy controls access without changing behavior (java.lang.reflect.Proxy, lazy/remote/security gates).
What are the design trade-offs of the Decorator pattern, and what criticisms apply to the java.io stream API specifically?
basics
~20 sDecorator gives flexible, runtime-composable features without a class explosion, following open/closed. The cost: many small objects, deep stacks that are hard to read and debug, easy-to-misorder wrapping, and lost object identity. The java.io API is often criticized for confusing, verbose wrapping with too many similar classes.
What is the Proxy design pattern, and what does it look like in Java?
basics
~20 sA proxy is a stand-in object that has the same interface as a real object. Calls go to the proxy first, which can add behavior (security checks, logging, lazy loading) and then forward to the real object.
How do java.lang.reflect.Proxy and InvocationHandler create a dynamic proxy, and what are the constraints?
basics
~10 sProxy.newProxyInstance generates a class at runtime that implements your interfaces. Every method call on it is routed to one InvocationHandler.invoke(proxy, method, args) method, where you add logic and usually call method.invoke(target, args) to delegate.
How do you tell Proxy and Decorator apart, given they are structurally almost identical in Java?
basics
~20 sBoth wrap an object of the same interface and forward calls. The difference is intent: a Decorator adds new behavior and is meant to be stacked, while a Proxy controls access (lazy creation, permissions, remoting) and is meant to be invisible to the caller.
How is the Proxy pattern used to implement cross-cutting concerns in Java frameworks, and what are the design trade-offs and pitfalls of pervasive proxying?
basics
~20 sFrameworks like Spring wrap your beans in proxies so they can run extra code (transactions, security, caching, logging) around your methods without you writing it. The cost: proxies only intercept calls that come through them, add reflection overhead, and make stack traces noisier.
What is the Facade design pattern, and where do you see it in the Java standard library (JDK)?
basics
~20 sA Facade is one simple class or method that hides a messy group of lower-level classes behind an easy entry point. In the JDK, java.nio.file.Files and the newer HttpClient are facades over more granular machinery.
How does the Facade pattern differ from Adapter and Proxy, and why does the distinction matter when reading JDK APIs?
basics
~20 sFacade simplifies a complex subsystem behind one easy interface. Adapter changes one class's interface into a different one the caller expects. Proxy stands in for an object to control access (lazy, remote, security). All three wrap something, but for different reasons.
Using java.nio.file.Files and HttpClient as examples, explain the trade-offs of using a JDK facade versus dropping down to the underlying subsystem.
basics
~20 sFacades like Files.readAllLines or HttpClient.send make the common case a one-liner and handle resource cleanup for you. But they load everything eagerly or assume defaults. For huge files, custom buffering, memory-mapping, or fine HTTP control, you drop to FileChannel/SocketChannel and configure it yourself.
What principles guide designing a good facade over a subsystem in your own Java library, and what failure modes should you avoid?
basics
~20 sMake the facade cover the common case with a tiny, intention-revealing API, but keep the underlying subsystem usable for advanced needs. Don't let the facade become a giant 'god object' that everyone depends on and that keeps growing.
What is the Composite design pattern, and how does Java's AWT/Swing Component/Container hierarchy illustrate it?
basics
~20 sComposite lets you treat a single object and a group of objects the same way. In Swing, both a single widget (like a JButton) and a container of widgets (like a JPanel) are Components, so code can handle either through the same Component type.
Why does java.awt.Container extend Component instead of simply holding a list of Component children, and what does that buy you?
basics
~20 sBecause a Container 'is-a' Component, you can put a container anywhere a component is expected — including inside another container. That is what lets panels nest inside panels and makes the UI a deep tree instead of one flat list.
How does an operation like painting or layout propagate through a Swing component tree, and why is that propagation a consequence of the Composite pattern?
basics
~20 sWhen you paint or lay out a container, it does its own work and then asks each child to do the same; if a child is itself a container, it repeats the process. This recursion walks the whole tree, and it works because every node is a Component, so the same call applies to leaves and groups alike.
Explain the transparency-vs-safety trade-off in the Composite pattern and how AWT/Swing resolves it.
basics
~20 sTransparency means leaves and composites share the exact same interface (including add/remove), so clients never branch — but leaves get child methods that do nothing or fail. Safety means add/remove live only on the composite, so you can't misuse them, but clients must know they hold a composite. AWT puts add/remove on Container (safety) while keeping paint/visibility on Component (transparency).
When is the Composite pattern the right choice, when is it a mistake, and what design pressures does a uniform Component interface create at scale?
basics
~20 sUse Composite when your data is a genuine part-whole tree and clients should treat one item and a group of items the same way (UIs, file systems, document models). Avoid it when the structure isn't really a tree, when leaves and composites differ too much to share an interface honestly, or when forcing uniformity bloats the base type with methods most nodes don't need.
How does Bridge differ from Adapter, especially in terms of when each is introduced into a Java codebase?
basics
~20 sAdapter makes an existing class with the 'wrong' interface fit something you already have — it's added after the fact to bridge a mismatch. Bridge is planned from the start to keep an abstraction and its implementation separate so both can grow independently.
What is the 'class explosion' problem, and how does Bridge avoid it in a Java design?
basics
~20 sIf something changes along two directions and you make a subclass for every combination, the number of classes multiplies (M×N). Bridge puts each direction in its own group and links them with a reference, so you only need M+N classes.
What problem does the Bridge pattern solve, and how does it structure a solution in Java?
basics
~20 sBridge splits one thing into two parts that can change separately: an abstraction (the 'what') and an implementation (the 'how'). The abstraction holds a reference to the implementation, so you can mix and match them instead of writing a class for every combination.
Walk through the participants of the Bridge pattern and how you wire them together in Java.
basics
~20 sThere are four roles: the abstraction (the high-level interface clients use), refined abstractions (its concrete subclasses), the implementor (the low-level interface), and concrete implementors. The abstraction stores an implementor reference, usually passed in through its constructor, and calls it to do the real work.
When should you reach for Bridge over plain inheritance, Strategy, or Adapter — and when is it the wrong tool?
basics
~20 sUse Bridge when a type varies along two independent dimensions you expect to keep growing, so you split them to avoid a subclass explosion. Don't use it for a single varying dimension, a quick fix to a mismatched API (Adapter), or just swapping one algorithm (Strategy).
Why does == sometimes work and sometimes fail when comparing two equal Integer values?
basics
~20 sSmall boxed Integers (-128 to 127) come from a shared cache, so == compares the same object and returns true. Larger values are separate objects, so == returns false even when the numbers are equal. Always use equals().
What is the Flyweight pattern, and where does the JDK use it for boxed integers?
basics
~10 sFlyweight reuses shared, unchangeable objects instead of creating new ones. The JDK does this for small Integer values: Integer.valueOf for numbers -128 to 127 returns the same cached object every time.
What autoboxing pitfalls beyond == can the Integer cache and wrapper types introduce?
basics
~10 sAutoboxing can silently create many objects (slow loops), throw NullPointerException when unboxing a null wrapper, and cause confusing == results. Use primitives in hot loops and equals() or Objects.equals() for comparison.
How is the Integer cache implemented internally, and what is and isn't configurable about it?
basics
~20 sInteger holds a static IntegerCache: an array of pre-built Integer objects for -128 up to a high bound (default 127). valueOf indexes into it. The low bound -128 is fixed; only the high bound is configurable via a JVM flag.
When would you design your own Flyweight cache like the Integer cache, and what are the tradeoffs and risks?
basics
~20 sBuild your own cache when you create many identical, immutable objects and allocation/memory is a real cost — for example interning common values. Make the objects immutable, document that == is unreliable, and avoid leaking mutable or unbounded caches.
Why were java.util.Observable and java.util.Observer deprecated in Java 9, and what should you use instead?
basics
~20 sThe old Observable/Observer classes were deprecated in Java 9 because they were weak and limited: Observable is a class (so you must extend it), it isn't thread-safe in a useful way, and it passes plain Object events. Use listeners, PropertyChangeSupport, or the reactive Flow API instead.
How does the JavaBeans PropertyChangeSupport / PropertyChangeListener mechanism implement the Observer pattern, and how do you use it correctly?
basics
~20 sA bean keeps a PropertyChangeSupport helper object. Listeners register with addPropertyChangeListener. When a property changes, the bean calls firePropertyChange(name, oldValue, newValue), and every listener's propertyChange method runs with a PropertyChangeEvent. It only fires when old and new values actually differ.
What is the java.util.concurrent.Flow API, and how do Flow.Publisher, Flow.Subscriber, and Flow.Subscription cooperate to deliver backpressure?
basics
~20 sFlow (added in Java 9) is the JDK's reactive-streams API: a Publisher produces items, a Subscriber consumes them. When you subscribe, you get a Subscription and must call request(n) to ask for n items — the publisher only sends up to what you requested. That request mechanism is backpressure, so a fast producer can't overwhelm a slow consumer.
How do Swing listeners (e.g. ActionListener) embody the Observer pattern, and why is the event-dispatch thread central to using them safely?
basics
~20 sA Swing component (the subject) keeps a list of listeners. You register one with e.g. button.addActionListener(...). When the user acts, the component fires an event and calls each listener's callback. All this runs on the Event Dispatch Thread (EDT), so listener code must stay on that thread and not block it.
When designing notification in modern Java, how do you choose between synchronous listeners (PropertyChangeListener/Swing), the reactive Flow API, and avoiding the deprecated Observable — and what trade-offs drive the choice?
basics
~20 sUse synchronous listeners (PropertyChangeListener, Swing) for simple in-process events where the producer can safely call observers directly. Use the Flow reactive API for asynchronous streams of many items where a slow consumer needs backpressure. Never base new code on the deprecated java.util.Observable.
How is Comparator an example of the Strategy pattern in the JDK, and how do you use it to vary sort order at runtime?
basics
~20 sA Comparator is a small object that says how to order two items. You pass different Comparators to Collections.sort or List.sort to get different orderings without changing the sort code. That swappable rule is the Strategy pattern.
Why do lambdas and functional interfaces make passing a strategy lightweight in Java, compared with the classic Strategy implementation?
basics
~20 sA functional interface has just one method, so instead of writing a whole class to hold a strategy, you can write it inline as a short lambda. Comparator is functional, so 'sort by age' becomes one line instead of a new class.
How do you build a multi-key, mixed-direction ordering using Comparator combinators, and what are the correctness pitfalls?
basics
~10 sChain Comparators: start with Comparator.comparing(key1), add .thenComparing(key2) for tie-breaks, and use .reversed() to flip a direction. Be careful where .reversed() applies and handle nulls explicitly so sorting doesn't throw.
When should you design an API to accept a Strategy (like Comparator) versus using inheritance/Template Method, and what are the trade-offs of behavior-as-a-parameter?
basics
~20 sUse a Strategy (pass behavior in, like a Comparator) when callers need to vary one step at runtime and combine behaviors freely. Use inheritance/Template Method when the variation is a fixed family known at design time. Strategy favors composition over subclassing.
What is the Template Method pattern, and how does a Java abstract class express it?
basics
~20 sTemplate Method is a pattern where a parent class writes the fixed steps of an algorithm in one method and leaves a few specific steps for subclasses to fill in. In Java you use an abstract class: a final/concrete method holds the skeleton and calls abstract methods the subclass must implement.
How does AbstractList use Template Method, and what does a minimal immutable List subclass look like?
basics
~20 sAbstractList already writes most of the List methods (iterator, indexOf, equals, etc.) using two abstract steps you provide: get(index) and size(). To make a read-only list you extend AbstractList and implement just those two methods.
What is the difference between an abstract primitive method and a hook method in Template Method, and how does the JDK use each?
basics
~20 sA primitive is an abstract step the subclass must implement. A hook is a step with a default body in the base class, so overriding it is optional. The template method calls both; hooks let subclasses tweak behavior without being forced to.
How does Template Method differ from the Strategy pattern, and when would you choose composition over an abstract-class hierarchy?
basics
~20 sTemplate Method varies steps using inheritance: a subclass overrides abstract methods, fixed at compile time. Strategy varies behavior using composition: you pass in an object (or lambda) that can change at run time. Prefer Strategy when you need flexibility or want to avoid deep class hierarchies.
What are the design pitfalls of Template Method, and how do calling overridable methods from a constructor or self-use affect a Java abstract-class skeleton?
basics
~20 sTemplate Method ties subclasses tightly to the base class, so base changes can break them. A key Java trap: if a constructor (or initializer) calls an overridable method, the subclass's override runs before the subclass's own fields are initialized, leading to bugs. The skeleton's protected methods become a contract you must document and keep stable.
What are the Iterator and Iterable interfaces in Java, and how do they relate to each other and to the Iterator design pattern?
basics
~20 sIterable means 'can be looped over' — it has one method, iterator(), that hands you an Iterator. The Iterator does the actual walking with hasNext() and next(). The for-each loop uses both behind the scenes.
Explain Java's fail-fast iterators and ConcurrentModificationException. When is it thrown, and what guarantees does it actually provide?
basics
~10 sMost java.util collections return 'fail-fast' iterators. They count structural changes (modCount). If the collection is changed during iteration by anything other than the iterator's own remove(), the next next()/hasNext() throws ConcurrentModificationException.
How does the Java compiler translate an enhanced for-each loop, and what are the practical consequences of that translation?
basics
~10 sThe compiler rewrites for-each into a while loop that calls iterator() once, then loops on hasNext()/next(). Because you have no visible iterator handle, you cannot safely remove elements with the collection's remove() inside it.
What does ListIterator add over the basic Iterator, and when would you reach for it?
basics
~20 sListIterator is a more powerful cursor for lists. On top of hasNext()/next(), it can go backwards (hasPrevious()/previous()), report indices, replace the current element with set(), and insert with add(). You get it from a List via listIterator().
How would you make your own class iterable so it works with for-each, and what contract must your Iterator honor?
basics
~10 sImplement Iterable<T> and return an Iterator<T> from iterator(). The iterator's hasNext() must report whether more elements remain, and next() must return the next one (or throw NoSuchElementException when none). Then for-each just works.
What is the Command design pattern, and how do Java's Runnable and Callable embody it?
basics
~20 sThe Command pattern wraps a request as an object so you can pass it around, store it, and run it later. In Java, Runnable and Callable are command objects: each bundles a piece of work in one method (run or call) that something else executes when it chooses.
When submitting tasks to an ExecutorService, how do execute(Runnable) and submit(...) differ, and what does submit return?
basics
~20 sexecute(Runnable) just runs the task and returns nothing. submit(...) accepts a Runnable or Callable and returns a Future you can use to wait for completion, get a Callable's result, or cancel the task. submit also captures exceptions inside the Future instead of letting them escape.
How does the executor framework let Command objects be deferred, queued, or scheduled, and which executor supports delayed/periodic execution?
basics
~20 sBecause tasks are objects, an executor can hold them in a queue and run them when a thread is free (deferred/queued). For time-based running, ScheduledExecutorService lets you schedule a task to run after a delay or repeatedly at a fixed rate or fixed delay.
When a ThreadPoolExecutor's queue and pool are full, what happens to a submitted Command, and how is that behavior controlled?
basics
~20 sIf all threads are busy and the work queue is full, the executor can't accept the task, so it applies a rejection policy. The default policy throws RejectedExecutionException. You can choose other policies, like running the task on the caller's thread or silently discarding it.
How do Java's Runnable/Callable + executors compare to the textbook Command pattern, and which classic capabilities (like undo) do they not directly provide?
basics
~20 sRunnable and Callable are command objects and executors are the invoker, so they cover the core Command pattern: requests become objects you can queue, defer, and run elsewhere. But the textbook pattern often adds undo/redo and explicit receivers; Runnable has only one execute-style method, so undo and history aren't built in — you'd add them yourself.
What is the State design pattern, and how does it let an object change its behavior when its internal state changes?
basics
~20 sThe State pattern lets an object behave differently depending on what 'mode' it is in. Each mode is its own object with its own version of the methods, and the main object hands work to whichever mode it currently holds.
How does a JDBC Connection illustrate state-dependent behavior, and what happens when you call methods after closing it?
basics
~20 sA JDBC Connection is either open or closed. While open you can run queries; once you call close(), the same methods become illegal and throw SQLException. So the connection's behavior depends on its open/closed state.
State and Strategy patterns are structurally almost identical. How do they differ, and how do you decide which one you're using?
basics
~20 sThey look the same — both delegate to a swappable object behind an interface. The difference is intent: Strategy is an algorithm the client picks and usually keeps fixed; State is a mode the object switches between itself as conditions change, with the states often driving the transitions.
In Java, what are the trade-offs of implementing a State machine with an enum versus separate state classes (or a sealed interface)?
basics
~20 sJava enums can give each constant its own method body, making a compact, type-safe state machine with no extra files — great for a fixed set of simple states. Separate classes or a sealed interface scale better when states hold their own data or have rich behavior.
When designing a State machine in Java, how do you handle illegal transitions and enforce invariants safely across states?
basics
~20 sMake illegal moves impossible or loud: each state only implements the operations valid in it, and invalid operations throw a clear exception (like IllegalStateException) instead of silently doing the wrong thing. Keep states immutable and validate transitions in one place.
What is the Chain of Responsibility pattern, and how do Servlet Filters embody it?
basics
~20 sIt is a design pattern where a request passes through a series of handlers, and each one decides whether to process it or pass it along. Servlet Filters are a chain: each filter can act on a request, then call the next one.
How is the order of Servlet Filters determined, and why does order matter?
basics
~20 sIn web.xml, filter order follows the order of the <filter-mapping> elements. With annotations or Spring, you set order explicitly (e.g. @Order or a FilterRegistrationBean). Order matters because earlier filters can short-circuit or change the request before later ones see it.
Write a Servlet Filter that logs request method/URI and elapsed time, and explain the before/after structure.
basics
~20 sImplement Filter.doFilter: record the start time, call chain.doFilter to run the rest of the chain, then in a finally block compute elapsed time and log the method, URI, and duration. The code before the call is pre-processing; the code after is post-processing.
How does a Servlet Filter short-circuit the chain, and what are correct practices when doing so?
basics
~20 sA filter short-circuits by not calling chain.doFilter and instead producing the response itself — for example writing a 401 or sending a redirect. Then no later filter or the servlet runs. You must fully complete the response and not commit it twice.
Compare Servlet Filters with Spring HandlerInterceptors as implementations of Chain of Responsibility. When would you choose each?
basics
~20 sBoth let you run code around a request in a chain. Filters live in the servlet container and see every request (even static files), working with raw request/response. Spring HandlerInterceptors live inside Spring MVC and know which controller/handler will run. Use filters for low-level/global concerns, interceptors for MVC-aware logic.
What is the Visitor design pattern, and what problem does it solve in Java?
basics
~20 sVisitor lets you add new operations to a group of related classes without changing those classes. You put each operation in a separate 'visitor' object, and each element class has an accept method that calls the right visit method on the visitor.
Why does the Visitor pattern rely on double dispatch, and how is it implemented in Java?
basics
~20 sJava picks which method runs based on only one object's runtime type (the receiver). Visitor needs to choose based on two: the element type and the visitor type. The accept method does this in two steps — first dispatch on the element, then on the visitor — giving 'double dispatch'.
What is the Visitor pattern's central trade-off regarding adding new element types versus new operations?
basics
~20 sVisitor makes adding new operations easy (write one new visitor, touch no element classes) but makes adding new element types hard (you must add a visit method to every existing visitor). Plain polymorphism is the reverse.
How do Java sealed types and pattern-matching switch provide a modern alternative to the Visitor pattern, and when would you still prefer classic Visitor?
basics
~20 sA sealed interface lists all its permitted subtypes, so a pattern-matching switch over them can be checked by the compiler for completeness. You write each operation as a switch instead of a visitor, with no accept methods — cleaner for adding operations, while the compiler still flags you when a new element type is added.
Give a concrete example of the Visitor pattern in the JDK and explain how it works there.
basics
~20 sThe NIO file API uses it: Files.walkFileTree takes a FileVisitor. As the JDK walks a directory tree, it calls your visitor's methods (visitFile, preVisitDirectory, etc.) for each entry, so you supply the operation and the JDK supplies the traversal.
What is the Mediator design pattern, and what problem does it solve in object-oriented Java code?
basics
~20 sMediator is a behavioral pattern where objects don't talk to each other directly. Instead, they talk through a central object called the mediator. This reduces tangled connections, so each object only knows the mediator, not all the others.
Show how a Mediator coordinates Swing components, and explain what each colleague is responsible for.
basics
~20 sA dialog acts as the mediator and holds its buttons, text fields, and checkboxes. Each component, on change, just tells the dialog. The dialog contains the rules (like enabling a button) and updates the other components. Components never reference each other.
Why can a Mediator degrade into a 'god object', and how do you keep it from happening?
basics
~20 sBecause the mediator collects all the interaction rules in one class, it keeps growing as you add features. Eventually it knows and controls everything — a god object. Prevent it by keeping each mediator small and focused, splitting big ones into smaller mediators.
Compare Mediator with Observer and Facade in Java. When would you pick each?
basics
~20 sMediator centralizes two-way coordination between peers that all know the mediator. Observer is one-way broadcast: a subject notifies subscribers that don't know each other. Facade is a simple front door to a subsystem; the subsystem doesn't know the facade. Pick by direction and who knows whom.
As a tech lead, when would you avoid introducing a Mediator, and what alternatives would you weigh?
basics
~20 sAvoid a Mediator when objects barely interact — the extra indirection just adds a class and hides simple calls. Also avoid one giant mediator for a whole system. Alternatives: keep direct calls when simple, or use an event bus for loose, many-to-many communication.
What is the Memento design pattern, and what are its three roles in Java?
basics
~20 sMemento lets you save an object's state to a separate object and restore it later (e.g. undo), without exposing the object's internals. The three roles are Originator (owns the state), Memento (the saved snapshot), and Caretaker (holds mementos but never reads them).
How do you implement a Memento in Java so that only the Originator can access the snapshot's state while the Caretaker still cannot read it?
basics
~20 sMake the Memento a private (or private static) nested class of the Originator and expose it to the outside only through a public marker interface. The Originator can read the nested class's private fields; the Caretaker holds it as the marker type and can't see anything.
What are the trade-offs between a serialization-based memento and a private field-snapshot memento in Java?
basics
~20 sA field-snapshot copies chosen fields by hand: fast, small, but you must write and maintain the copy code. A serialization-based memento serializes the whole object to bytes: automatic deep copy and no per-field code, but slower, larger, and needs Serializable.
For an undo feature, when would you choose Memento (snapshots) over a Command-based approach, and how can the two combine?
basics
~20 sMemento undoes by restoring a saved full state; Command undoes by storing each operation and applying its inverse. Use Memento when full snapshots are cheap and inverses are hard to compute; use Command when state is large but each change is small. They combine: a Command can store a Memento to undo itself.
An undo feature built on full-state mementos is consuming too much memory in production. How do you diagnose and reduce the cost while keeping correctness?
basics
~20 sEach memento is a full copy of state, so an unbounded history grows memory linearly. Fix it by bounding history depth, storing deltas instead of full snapshots, sharing immutable sub-state structurally, or moving older snapshots off-heap/to disk — choosing based on how big state is and how it changes.