Suppose a checkout service calculates shipping through a ShippingPolicy interface. The goal is to vary behavior without making the checkout workflow depend on every carrier's API.
1. Choose the implementation at a boundary
Composition code reads configuration and constructs either a standard-rate policy or a carrier-backed policy. It passes the selected implementation into the checkout service. The business service depends on the interface it needs rather than selecting infrastructure internally.
2. Call the contract
Checkout invokes quote(order) through the interface. The call site knows what inputs and result the contract requires, but does not know how the concrete implementation calculates the quote.
3. Dispatch and perform work
The runtime dispatches to the object's concrete method. One implementation may use a table of fixed rates; another may make a network call, apply a timeout, and translate a provider response. The abstraction does not erase the difference in latency or failure behavior.
4. Return across the boundary
The implementation returns a domain-level quote or a typed failure. Checkout decides whether to continue, ask the user, or fall back. Tests can inject a deterministic policy, while integration tests verify the real adapter's translation.
This pattern is useful when behavior truly varies. If there is only one stable behavior and no expected change, the extra interface can add indirection without protecting a meaningful boundary.