没错,我们想要独立测试Build方法,但是现在SearchCriteriaBinder还不允许我们这么做。那么,继续重构吧:
internal interface ISearchCriteriaBuilder { SearchCriteria Build(List<string[]> tokenGroups); } internal class SearchCriteriaBuilder : ISearchCriteriaBuilder { internal SearchCriteriaBuilder() : this(GetConverter) { } internal SearchCriteriaBuilder(Func<string, IConverter> converterGetter) { this.m_getConverter = converterGetter; } internal static IConverter GetConverter(string field) { // 使用if ... else或是字典 } private readonly Func<string, IConverter> m_getConverter; public SearchCriteria Build(List<string[]> tokenGroups) { ... } } |
把Build的逻辑独立提取成类之后,自然需要让SearchCriteriaBinder使用SearchCriteriaBuilder:
public class SearchCriteriaBinder : IModelBinder { public SearchCriteriaBinder() : this(new Tokenizer(), new SearchCriteriaBuilder()) { } internal SearchCriteriaBinder(ITokenizer tokenizer, ISearchCriteriaBuilder builder) { this.m_tokenizer = tokenizer; this.m_builder = builder; } private readonly ITokenizer m_tokenizer; private readonly ISearchCriteriaBuilder m_builder; public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var modelName = bindingContext.ModelName; var rawValue = bindingContext.ValueProvider[modelName].RawValue; var text = HttpUtility.UrlDecode(rawValue.ToString()); var tokenGroups = this.m_tokenizer.Tokenize(text); return this.m_builder.Build(tokenGroups); } } |