Design patterns
- Typed key pattern. Query inputs and outputs are stored in
ParamsunderParamKey<T>instances. Each key declares its value type, so reads return the correct type without casting. Keys are defined as static readonly fields inQueryKeys, with names built from constants inQueryKeyNames. - Static facade.
QueryFactoryexposes static methods such asGetCurrentLevel(). Each method builds a query, sends it, and returns the typed value, so callers never handle the message directly. - Read-only message. A query is a message whose handler answers it by filling in
ResultandStatus. TheIQuerydocumentation states that handlers must not change state while answering. This rule is a documented convention and is not enforced by any code in these blocks. - Routing by key with queuing. The query bus routes each query by
TargetDomainto a single registered handler. If no handler exists, or the domain is not ready, the query is queued. The routing and queuing logic lives in the message bus base class (dependency).
Connections to dependencies
- Contracts (Domain).
Query.TargetDomainis aDomainvalue. Each factory method picks the domain that owns the data, such asDomain.Levelfor time in level andDomain.Gamefor current level and game speed. - Params.
Query.ParamsandQuery.ResultareParamsinstances. Keys fromQueryKeysare passed toSet,Get, andHas. - Bus (QueryBus, BusUtility, BusRegistry).
BusUtility.AskAndGetsends the query through the query bus and reads the result key from the answered query. The query bus is reached through the service locator, which holds the bus registry. Owning systems register their handlers on the query bus for their domain. - Bus (MessageBus). Queries that arrive before a handler exists, or before the domain signals ready, are queued in FIFO order and released when the handler registers or the ready signal is raised.
Key concepts and terminology
- Domain. The system that owns a category of data. Queries are addressed to a domain, not to a specific class.
- Verb. The kind of question:
Get,Own, orHas. The handling system decides what each verb means for its domain. OnlyGetis used byQueryFactory. - Subject. A value in
QuerySubjectsstored underQueryKeys.QuerySubjectin the input params. It tells the handler which data to return within its domain. - Params (input). Data the caller sets before sending, such as the subject.
- Params (result). Data the handler writes when answering. The caller reads it after sending.
- Status.
Pendinguntil answered. The handler may setSuccessorFailure. The status documentation describes yes-or-no answers, but no query in these blocks usesOwnorHas. - Ready signal. An optional signal that gates a domain's queue, set through the message bus base class (dependency).
Event and data flow
- A caller invokes a
QueryFactorymethod, such asGetTimeInLevel(). - The factory creates a
Querywith the target domain andQueryVerb.Get. - The factory sets
QueryKeys.QuerySubjectin the input params to the matchingQuerySubjectsvalue. - The factory calls
BusUtility.AskAndGet, which sends the query to the query bus and gets back the answered query. - The query bus routes the query by
TargetDomain. - If a handler exists and is ready, the handler fills in the result params and status. The answered query is returned to the caller.
- If no handler exists, or the domain is not ready, the query is queued.
- When the handler registers, or the ready signal is raised, queued queries are routed in FIFO order.
AskAndGetreads the value under the result key and returns it as the key's type.
Thread safety
Not addressed in the code for this system.