A dispatcher conditional plus N inline handler methods the agent must scan together to know what runs for a given command. Adding a command edits two places (dispatcher plus host class), and the host file grows by one handler body for every new command added.
One file per command the agent reads in isolation; the dispatcher reads a registry of commands instead of a switch over IDs, and adding a command is one new class plus one registry entry rather than an edit across every dispatcher branch.
Before the refactoring
// One processor with a long dispatch conditional plus all handler bodies.class CommandProcessor {execute(command, payload) {if (command === 'create-user') return this.createUser(payload);if (command === 'delete-user') return this.deleteUser(payload);if (command === 'reset-password') return this.resetPassword(payload);if (command === 'update-profile') return this.updateProfile(payload);throw new Error(`unknown command ${command}`);}createUser(payload) { /* ... */ }deleteUser(payload) { /* ... */ }resetPassword(payload) { /* ... */ }updateProfile(payload) { /* ... */ }}
After the refactoring
// Each handler is a Command object; the registry replaces the conditional.class CreateUserCommand {execute(payload) { /* ... */ }}class DeleteUserCommand {execute(payload) { /* ... */ }}class ResetPasswordCommand {execute(payload) { /* ... */ }}class UpdateProfileCommand {execute(payload) { /* ... */ }}class CommandProcessor {constructor() {this.commands = new Map([['create-user', new CreateUserCommand()],['delete-user', new DeleteUserCommand()],['reset-password', new ResetPasswordCommand()],['update-profile', new UpdateProfileCommand()],]);}execute(command, payload) {const handler = this.commands.get(command);if (!handler) throw new Error(`unknown command ${command}`);return handler.execute(payload);}}
Cross-command invariants (e.g., 'every command logs') cannot be statically enforced when handlers are loose methods on the dispatcher. The agent must hold the full handler set in context to verify any cross-command concern; refactoring one handler risks unintended impact on neighbouring branches that share helpers.
Command spreads handler logic across N files; the agent must traverse the registry to know which class handles a given command name. Stringy registry keys defeat static type analysis — typo-driven bugs slip past the type system.
Adding a new command is one new class plus one registry entry; the type checker confirms every Command implements execute, and cross-cutting concerns wrap the registry once instead of being duplicated per dispatch branch.
Many trivial Commands (`class XCommand { execute() { return X(); } }`) raise context cost without buying anything — the agent loads one definition per command name to verify what it does. The pattern's gain materializes when commands carry meaningful state or when cross-cutting concerns reuse the uniform interface.