设计模式选型咨询:匹配查找功能的代码结构优化建议
Great question—let's unpack your scenario and figure out the best pattern fit here. You've got a class that loads configuration options from JSON, matches them against a bunch of input parameters, and spits out a configured Tool instance. Let's break down whether a service class, factory, or combination makes sense.
1. Start with Single Responsibility: Split Your Logic
Don't cram all functionality into one class—split it into focused components that each do one job:
- Option Config Loader: A dedicated class to handle loading and parsing the JSON into
List<Option>. This keeps configuration logic isolated, so if you ever need to switch to a database or remote API for configs, you only modify this class.public class OptionConfigLoader { public List<Option> LoadFromJson(string filePath) { // JSON read + deserialization logic here } } - Option Matcher: A class solely responsible for the complex matching logic that finds the right Option based on your input parameters. This makes it easy to test matching rules independently without touching config or Tool creation code.
public class OptionMatcher { public Option FindMatch(List<Option> options, string value1, int value2, ... bool value20) { // Implement your parameter-based matching logic here } } - Tool Factory: This is where the Factory Pattern shines—this class's only job is to create and configure Tool instances using a matched Option.
public class ToolFactory { public Tool CreateConfiguredTool(Option matchedOption) { // Initialize Tool properties using the Option's config return new Tool { Options = matchedOption.ConfiguredSettings }; } }
2. Use a Service Class to Coordinate Everything
Your original BestOptionFinderService makes perfect sense as a top-level coordinator that ties these components together. It handles the workflow: load configs → match parameters → create Tool. Here's how it might look:
public class BestOptionFinderService { private readonly List<Option> _options; private readonly OptionMatcher _matcher; private readonly ToolFactory _toolFactory; // Inject dependencies (or initialize directly if you're not using DI) public BestOptionFinderService(OptionConfigLoader loader, OptionMatcher matcher, ToolFactory toolFactory) { _options = loader.LoadFromJson("/path/to/your/config.json"); _matcher = matcher; _toolFactory = toolFactory; } public Tool FindBestMatch(string value1, int value2, ... bool value20) { var matchedOption = _matcher.FindMatch(_options, value1, value2, ... value20); if (matchedOption == null) { // Handle no-match case: return default Tool, throw exception, etc. throw new InvalidOperationException("No matching option found for the provided parameters."); } return _toolFactory.CreateConfiguredTool(matchedOption); } }
3. Why This Structure Works
- Maintainability: Each component has a clear purpose, so debugging and updating logic (like changing matching rules) is far easier.
- Flexibility: Need to adjust how configs are loaded? Only touch the loader. Want to tweak Tool initialization? Only modify the factory.
- Testability: You can write unit tests for the matcher without loading real JSON, or test the factory without running the full matching logic.
4. Fix That Long Parameter List
20+ parameters in your FindBestMatch method is a code smell—wrap them into a single parameter object to clean things up:
public class ToolMatchParameters { public string Value1 { get; set; } public int Value2 { get; set; } public int Value3 { get; set; } // ... all other parameters here public bool Value20 { get; set; } }
Then update your method signature:
public Tool FindBestMatch(ToolMatchParameters parameters) { var matchedOption = _matcher.FindMatch(_options, parameters); // ... rest of the logic }
This makes the method cleaner and avoids breaking every caller when you add/remove a parameter later.
5. Service vs. Factory: Why Not Both?
A pure Factory Pattern is focused on object creation, but your workflow includes config loading and complex parameter matching—those aren't factory responsibilities. Using a service class to orchestrate the factory (and other components) is the sweet spot here. The factory handles the "how to create Tool" part, while the service handles the "when and which Tool to create" workflow.
内容的提问来源于stack exchange,提问作者user3250672

