我有一个叫做CommercialRiskProcessor
的课程。它只有221行,包括注释和using
。它只有3个注入参数,并且只做一件事-评估一些风险。实际上,它的接口只有一种方法:
public interface ICommercialRiskProcessor
{
Task<CommercialQuoteWithStatus> ApplyRules(CommercialRiskProcessorRequestInfo info, CommercialQuoteContext qtx, EFCommercialQuote quote);
}
因此,无论如何,它不是“神”类。它开始如下:
public class CommercialRiskProcessor : ServiceBase, ICommercialRiskProcessor
{
public const string UiHardDeclineMessage = WorkflowFailure.UiDefaultWorkflowFailureMessage;
protected ICommercialRiskRuleCollectionFactory RiskRuleCollectionFactory { get; }
protected ICommercialRiskRuleFactory RiskRuleFactory { get; }
protected ICommercialOverrideService OverrideService { get; }
public CommercialRiskProcessor(
ICommercialRiskRuleCollectionFactory riskRuleCollectionFactory,
ICommercialRiskRuleFactory riskRuleFactory,
ICommercialOverrideService overrideService)
{
RiskRuleCollectionFactory = riskRuleCollectionFactory;
RiskRuleFactory = riskRuleFactory;
OverrideService = overrideService;
}
public async Task<CommercialQuoteWithStatus> ApplyRules(CommercialRiskProcessorRequestInfo info, CommercialQuoteContext qtx, EFCommercialQuote quote)
{
var ruleCollection = await RiskRuleCollectionFactory.TryResolveService(info.RuleCollectionName, qtx, quote);
if (ruleCollection == null)
{
return new CommercialWorkflowFailure(UiNotSupportedStateMessage);
}
var results = await ApplyRules(ruleCollection, qtx, quote);
qtx.RuleEvaluationResults.AddRange(results);
return await ProcessResults(info, results, qtx, quote);
}
并且有一些私有方法可以进行一些额外的处理。这无关紧要。问题是我需要另一个风险处理程序,称为HomeownerRiskProcessor
。如果我复制/粘贴整个文件,然后将“ Commercial”重命名为“ Homeowner”,则新类将立即可用,因为在这两组类中所有支持类和属性都被相同地调用。然而,房主和商业阶层是非常不同的,因此所有底层对象都是不同的。
因此,复制/粘贴/单次替换似乎不是一种好的编码样式,不是吗?然而,利用代码重用的唯一可能方法似乎是引入泛型。这是一团糟的地方:风险处理器类中使用的每个方法/属性都必须经过generic
化,并引入了一些通用的通用接口。随后,使整个类成为通用类(包括私有成员)将需要10个以上带有多个通用约束的通用参数!显然,这远远超出了可读性,可能会使其比复制/粘贴/修改更糟。
我想知道是否还有其他解决方案可以实现代码重用,但是在单个代码中没有太多的通用参数。
如果我复制/粘贴整个文件,然后将“ Commercial”重命名为“房主”,那么新类将立即可用,因为所有在这些中,支持类和属性的名称相同两组班。然而,房主和商业阶层非常不同,因此所有基础对象都不同。
听起来,即使这些类非常不同,您也可以从它们中提取相同的接口。您只需要将接口限制为仅风险处理所需的方法即可。然后,风险处理器可以对实现这些接口的任何类进行操作。
这里不需要泛型。
下面的代码对您有用吗?基本上,您对接口所做的全部工作就是设置一个模板,该模板必须至少遵循该模板。
public interface IRiskProcessor<TQuoteWithStatus, TRiskProcessorRequestInfo, TQuoteContext, TEFQuote>
{
Task<TQuoteWithStatus> ApplyRules(TRiskProcessorRequestInfo info, TQuoteContext qtx, TEFQuote quote);
}
public interface ICommercialRiskProcessor : IRiskProcessor<CommercialQuoteWithStatus, CommercialRiskProcessorRequestInfo, CommercialQuoteContext, EFCommercialQuote>
{
Task<CommercialQuoteWithStatus> ApplyRules(CommercialRiskProcessorRequestInfo info, CommercialQuoteContext qtx, EFCommercialQuote quote);
}
public interface IHomeOwnerRiskProcessor : IRiskProcessor<HomeOwnerQuoteWithStatus, HomeOwnerRiskProcessorRequestInfo, HomeOwnerQuoteContext, EFHomeOwnerQuote>
{
Task<HomeOwnerQuoteWithStatus> ApplyRules(HomeOwnerRiskProcessorRequestInfo info, HomeOwnerQuoteContext qtx, EFHomeOwnerQuote quote);
}