我有两种类型,即AdditionCalc
和AggregateCalc
,它们有两种方法:
代码:
public abstract class BaseCalculator
{
private readonly IVersion _version;
protected BaseCalculator(IVersion version)
{
this._version = version;
}
public void Calculate(Request r)
{
CalculateInternal();
//version code here
}
protected abstract void CalculateInternal(Request r);
public abstract StatisticsModel Calculate(StatisticsRequest model);
}
public class AdditionCalc : BaseCalculator
{
public AdditionCalc() : base(new Version(ConfigurationManager.ConnectionStrings["dbConnectionString"].ConnectionString)) { }
public override StatisticsModel Calculate(StatisticsRequest model)
{
//no version code here
}
}
public class CalculatorFactory
{
public BaseCalculator GetCalculatorByType(int type)
{
switch (type)
{
case (int)Types.Addition:
return new AdditionCalc();
case (int)Types.Aggregate:
return new AggregateCalc();
}
}
}
现在的问题是当我调用返回Calculate
的{{1}}方法时,我不想调用基本构造函数,因为对于此方法,我不需要版本代码,但是每次调用此方法,默认构造函数将被调用并初始化StatisticsModel
。
这就是我调用适当的version variable of base class
方法的方式:
Calculate
注意:我不想通过调用代码传递版本依赖项。
那么我该如何设计以上代码,以使不会为返回var calculatorFactory = new CalculatorFactory();
var type = calculatorFactory.GetCalculatorByType((int)Types.Addition);
type.Calculate(StatisticsRequest);
的{{1}}方法调用Version代码?
更新:
Calculate
答案 0 :(得分:3)
您的两个计算器类不应相互关联。它们应该实现一个通用的接口,但不共享通用的逻辑。
因此,您将有一类支持版本控制的东西,而另一类对版本控制一无所知。每个对象都100%专注于自己的逻辑,而不必彼此耦合/关联或交互。
如果您以后确实有一些常见行为,请确保它确实是常见行为,并将其放在两个类都继承的基类中。
到现在为止,您将覆盖版本控制行为(甚至不完全)。使用继承时,您想添加功能,而不是减去功能,这就是您当前模型正在做的事情。
看看SOLID以获得更多指导。
考虑,
interface ICalculator
{
void Calculate() { ... }
}
abstract class CalculatorThatCaresAboutVersion : ICalculator
{
void CalculatorThatCaresAboutVersion(IVersion version) { ... }
}
abstract class CalculatorThatDoesntCareAboutVersion : ICalculator
{
void CalculatorThatDoesntCareAboutVersion() { ... }
}
您有两种不知道或不在乎其他种类的计算器。您可以根据需要从它们那里继承,并且与版本关联的操作与其他计算器中的操作没有任何关系。
这使您可以自由地按需实现每个对象,而又不影响其他对象:没有诸如“如果我不关心它该如何不初始化版本”之类的问题?由于自然存在关注点分离,因此问题甚至根本不会出现。
答案 1 :(得分:1)
如果我没记错的话,您只需要Calculate(Request r)
的版本,而不需要Calculate(StatisticsRequest model)
的版本
此外,您还可以将依赖项隐藏在您使用的类中,即您不希望客户端代码通过版本(这可能不是一个好主意)。
如何删除IVersion
的{{1}}参数并在BaseCalculator
方法中检索所需的值?
像这样:
Calculate
受保护的public abstract class BaseCalculator
{
private readonly IVersion _version;
protected BaseCalculator()
{
}
public void Calculate(Request r)
{
this._version = GetVersion();
CalculateInternal();
//version code here
}
protected virtual void GetVersion() //protected virtual or abstract, pick the best for your scenario.
{
return new Version(ConfigurationManager.ConnectionStrings["dbConnectionString"].ConnectionString);
}
protected abstract void CalculateInternal(Request r);
public abstract StatisticsModel Calculate(StatisticsRequest model);
}
方法可以在派生类中重写(或者,如果您的GetVersion
不知道如何创建BaseCalculator
对象,则可以是抽象方法,强制派生类提供实施方案。
答案 2 :(得分:1)
您要解释的内容听起来像 optional 依赖项。
在不显着改变设计的情况下解决该问题的一种方法是将IVersion
的创建推迟到真正需要的时候,方法是将IVersion
的构造函数参数替换为某种工厂,例如{{ 1}},如果只需要创建一次,则最终将其与Func<IVersion>
字段组合。
例如像这样的东西:
Lazy<T>
以及需要public abstract class BaseCalculator
{
private readonly Func<IVersion> _versionFactory;
protected BaseCalculator(Func<IVersion> versionFactory)
{
_versionFactory = versionFactory;
}
}
IVersion
或
var version = _versionFactory();
// version code here
和
public abstract class BaseCalculator
{
private readonly Lazy<IVersion> _version;
protected BaseCalculator(Func<IVersion> versionFactory)
{
_version = new Lazy<IVersion>(versionFactory);
}
}
在两种情况下,派生类的构造函数代码都将是这样的(只需在当前基础调用代码之前添加var version = _version.Value;
// version code here
)
() =>
答案 3 :(得分:0)
要实现的目标将需要覆盖无法完成的基本构造函数,请参见this post。