iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
When a rental availability endpoint handles cars, motorcycles, and e-bikes, putting every eligibility check in one service method can make each new vehicle type harder to add safely. Separate the policy choices by vehicle type with Strategy, express reusable checks as rule objects, and collect failed checks as notifications. That structure is useful when policies genuinely differ or are likely to change; for a few stable variants, a straightforward conditional may be simpler.
Why a rental availability endpoint becomes coupled
In André Degaspari’s case study, a rental API started with cars, expanded to motorcycles, and then needed e-bike support. The vehicle types had different eligibility requirements, but the service method handled customer lookup, shared restrictions, vehicle-specific validation, and inventory lookup together. As those concerns accumulated, it became harder to see which checks applied to which vehicle and riskier to change one policy without affecting another.
The design problem is not simply that the method is long. It is that the method owns decisions that vary for different reasons: what is common to every rental, what is specific to one vehicle type, how failures are reported, and when inventory should be queried. The case study proposes making those decisions explicit.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11How the design separates policy from request flow
The service keeps the endpoint’s high-level sequence, while strategies and rule objects take responsibility for vehicle-specific eligibility. A strategy is selected for the requested type; it runs that type’s rules; failed rules add explanations to a notification collector. The service can then decide whether to query inventory and return the result in the API’s expected format.
#1 Best Overall
Rule objects represent individual checks
A rule encapsulates one eligibility condition, such as minimum age, license category, pending debits, or active violations. It receives the customer and a notification collector. If the customer fails that check, the rule adds an explanatory message rather than forcing the service to know the details of every condition.
These checks can be reused where the same policy applies to more than one vehicle type. Reuse does not mean every type must run every rule: each vehicle’s policy determines which checks belong in its set.
Strategies select the rules for each vehicle type
Each vehicle strategy chooses and executes the rules relevant to that type. In the case study’s example, the car strategy combines financial and violation checks with age and license checks, while the e-bike strategy applies a different subset. A shared strategy interface lets the service ask the selected policy to validate without embedding each vehicle’s rule list in the service method.
This is an application of the Strategy pattern: a family of behaviors is separated into interchangeable implementations, and the context delegates to the chosen implementation. See Refactoring.Guru’s Strategy reference for the pattern’s general structure and trade-offs.
A registry handles selection and unsupported types
A strategy registry maps the requested vehicle type to its strategy. Keeping this mapping separate makes the supported types and the unsupported-type path visible in one place instead of scattering type checks through validation logic. The endpoint still needs a deliberate API response for an unknown or unsupported type; the registry should not silently choose a default policy.
The service coordinates rather than owns every rule
The service’s remaining job is to load the customer, select the strategy, run validation, and decide whether availability should be queried. If validation fails, it returns the restriction reasons in the response shape the API defines. This leaves orchestration in the service and policy details in the components that own them.
Returning all eligibility failures in one response
A notification collector lets validation continue after one failed rule, so a client can receive multiple reasons in a single pass—for example, a failed age requirement and an unresolved restriction—rather than discovering each issue through repeated requests. This is useful when the client should explain how to resolve eligibility problems.
Recommended Free Tools
That behavior is a product and API decision, not an automatic benefit of using rule objects. Some endpoints should stop at the first failure for security, performance, or compatibility reasons. Decide whether to collect all failures or stop early, and preserve the existing response contract during a refactor unless changing it is intentional. Also define whether messages are intended for end users or internal diagnostics; those audiences may need different detail.
Rank #3
When Strategy and rule objects are worth the extra structure
Use the patterns when vehicle policies are meaningfully different, are expected to evolve independently, or need clear testing boundaries. A new vehicle type can then be represented by a strategy that selects its rules, while genuinely shared checks remain reusable.
Do not adopt the pattern just because a conditional exists. Refactoring.Guru cautions that when only a couple of algorithms exist and rarely change, adding classes and interfaces can overcomplicate the program. If there are only a few stable vehicle types, a clear conditional may be easier to read and maintain. The practical question is whether the policy variation is real and likely to grow—not whether Strategy is fashionable.
The case study also acknowledges that the refactored design introduces more classes and concepts, which may initially be harder to grasp. It reports reuse in additional use cases but provides no measured defect, speed, or maintenance outcomes. That experience is not quantitative proof that the pattern improves every rental API.
Rule objects are not automatically a rules engine
A set of ordinary domain-specific rule objects is a way to organize checks in application code. A rules engine is a different computational model, commonly based on production rules in which conditions trigger actions. Martin Fowler notes that rule chaining can make behavior difficult to reason about and debug, and argues that production-rule systems suit only a subset of problems. His discussion recommends keeping such systems within narrow contexts, limiting chaining where practical, and taking testing seriously because behavior may be implicit. Read Fowler’s Rules Engine essay.
Rank #4
Consider a general-purpose rules engine when rules need to be authored or changed outside the application’s normal code-release process, or when the domain genuinely benefits from that execution model. If evaluating an engine, compare it with a hand-built domain-specific approach using a prototype, as Fowler suggests. Do not introduce an engine merely to avoid a modest number of explicit checks.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Questions to settle before extracting the classes
Before refactoring, write down the policy and the contract the endpoint must preserve. This reduces the chance that moving code changes eligibility accidentally.
- Shared checks: Which restrictions apply to every vehicle type, and which are specific to cars, motorcycles, or e-bikes?
- Validation behavior: Should evaluation stop at the first failure, or collect all applicable failures?
- Response compatibility: What response shape, status, and message semantics do existing clients rely on?
- Evaluation order: Does order affect behavior, cost, or which messages are returned? Make the order explicit if it matters.
- Inventory timing: Should the endpoint query availability only after eligibility passes, or does the existing contract require another behavior?
- Tests: Test individual rules, each vehicle’s selected rule set, combinations of failures, unsupported types, and the service’s response behavior.
Keep existing policy behavior intact while relocating it. Treat a changed age threshold, license requirement, or notification contract as a separate policy change rather than an incidental part of the structural refactor.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →How to interpret the case study’s examples
Degaspari describes a real situation with more rules, microservice integrations, and a larger validation context than the simplified example. He says two developers implemented a module for their use cases and that he reused it elsewhere. The article also discloses that its code examples were AI-generated and that he did not write the example code. The examples are therefore best read as an illustrative design proposal, not as code he personally verified line by line or as a controlled comparison.
Any ages or license categories shown in the sample are fictional example policy values. They are not universal rental requirements, legal advice, or statements about a specific company or jurisdiction. Define those requirements from the applicable business policy and local rules.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

