Why DSLs Matter: Building a Simple, Stateless State Machine with Fluent APIs
This article explains the concept and benefits of domain‑specific languages, classifies DSL types, and demonstrates how to implement a lightweight, stateless state‑machine engine in Java using a fluent internal DSL that improves code readability, maintainability, and performance.
DSL (Domain Specific Language) is a tool that provides a clear way to communicate the intent of a specific part of a system.
What is DSL
A DSL is a programming language with limited expressiveness, focused on a particular domain, offering only the features needed for that domain.
DSL Classification
Internal DSL : A specific usage of a general‑purpose language, written as valid code but with a distinct style. The state machine presented is an internal DSL built on Java.
External DSL : A language separate from the host language, often using custom syntax or formats like XML.
Workbench : A dedicated IDE that visualizes DSL scripts.
Internal DSLs are the simplest to implement and cost‑effective, while workbenches provide configuration and visualization at higher implementation cost.
Fluent Interfaces
Fluent interfaces enable method chaining to create readable internal DSLs. Example using Mockito:
when(mockedList.get(anyInt())).thenReturn("element")Fluent APIs improve readability and act as an internal DSL for specific domains such as testing.
Stateless State Machine Design
The goal is a lightweight state machine that supports only simple state transitions and is stateless, allowing a single singleton instance to serve all requests.
Key model elements:
State
Event
Transition
External Transition
Internal Transition
Condition
Action
StateMachine
Core model code:
//StateMachine
public class StateMachineImpl<S,E,C> implements StateMachine<S,E,C> {
private String machineId;
private final Map<S, State<S,E,C>> stateMap;
...
}
//State
public class StateImpl<S,E,C> implements State<S,E,C> {
protected final S stateId;
private Map<E, Transition<S,E,C>> transitions = new HashMap<>();
...
}
//Transition
public class TransitionImpl<S,E,C> implements Transition<S,E,C> {
private State<S,E,C> source;
private State<S,E,C> target;
private E event;
private Condition<C> condition;
private Action<S,E,C> action;
...
}Fluent API for building transitions ensures correct call order:
class TransitionBuilderImpl<S,E,C> implements ExternalTransitionBuilder<S,E,C>, InternalTransitionBuilder<S,E,C>, From<S,E,C>, On<S,E,C>, To<S,E,C> {
@Override
public From<S,E,C> from(S stateId) { /* ... */ return this; }
@Override
public To<S,E,C> to(S stateId) { /* ... */ return this; }
...
}Usage example:
StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();
// external transition
builder.externalTransition()
.from(States.STATE1)
.to(States.STATE2)
.on(Events.EVENT1)
.when(checkCondition())
.perform(doAction());
// internal transition
builder.internalTransition()
.within(States.STATE2)
.on(Events.INTERNAL_EVENT)
.when(checkCondition())
.perform(doAction());
builder.build(machineId);By removing stateful fields (initial and current state) from the engine, the state machine becomes stateless, allowing a single instance to handle all requests and significantly improving performance.
Images illustrating the DSL hierarchy and state machine model:
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
