域模型的可配置显示属性



使用DDD并遵循干净的体系结构模式,我有点困惑于为特定域模型ID配置显示属性的理想位置。这听起来很困惑,我想我最好用一个例子来解释:

在这里,域模型的业务逻辑很简单:根据输入、增益和偏移量计算"缩放"值。

//Domain Model
public class Transducer
{
//Name is the ID
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double RawValue { get; set; }
public double ScaledValue { get; private set; }

public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}

我们有一个用例,它协调用户操作和域模型并管理持久性。这里的细节并不重要,所以我只包含了一个示例接口:

//implementation of execution of business logic and persistance would go in the implentation, details left out for this example
public interface ITransducerUseCase
{
IEnumerable<string> GetAllTransducerNames();
void AddNewTransducer(string Name, double Gain, double Offset);
void SetGain(string Name, double Gain);
void SetOffset(string Name, double Offset);
void SetRawValue(string Name, double Raw);
double GetScaledValue(string Name);
}

该用例由控制器用于将用例与视图或其他控制器进行协调。该特定控制器允许查看所有换能器名称,并可以更改其增益属性。

public class Controller
{
ITransducerUseCase _TransducerUseCase;
//these are sent to the view to be displayed
public Dictionary<string, double> _transducerScaledValues = new Dictionary<string, double>();
public Controller(ITransducerUseCase TransducerUseCase)
{
_TransducerUseCase = TransducerUseCase;
//Get all the names and populate the dictionary to display.
foreach (var transducerName in _TransducerUseCase.GetAllTransducerNames())
_transducerScaledValues.Add(transducerName, _TransducerUseCase.GetScaledValue(transducerName));
}
//bound to the view
public string SelectedName { get; set; }
//bound to the view, a property for setting a new gain value
public double Gain { get; set; }
public void OnButtonClick()
{
//update the gain
_TransducerUseCase.ChangeGain(SelectedName, Gain);
//get the new scaled value            
_transducerScaledValues[SelectedName] = _TransducerUseCase.GetScaledValue("PumpPressure");
}
}

这就是这个问题的脚手架。这是新的要求:

  • 我们希望为为的ScaledValue显示的"小数位数"CCD_ 2。所以一个Id为"PumpPressure"的DisplayRounding值可能与名称为"PumpTemperature"的传感器。

  • 此设置必须是应用程序范围的(任何时候值为显示,使用此设置(。如果ScaledValue曾经被记录到一个文件中,所以这是一个交叉业务需求。

我想到的解决方案:将特性放置在域模型中,并通过图层将其返回到视图中。这似乎不是一个合乎逻辑的地方,因为DisplayRounding属性与业务逻辑没有任何相关性。

public class Transducer
{
//This seems like an SRP violation
public int DisplayRounding { get; set; }
//Name is the ID
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double ScaledValue { get; private set; }

public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}

如果不在那里,那么在哪里

我们可以把它放在一个没有任何业务逻辑的单独的域模型中吗?持久性可以由同一个用例类或单独的用例类来管理。

public class TransducerDisplaySettings
{
public int Rounding { get; set; }
//plus other related properties
} 

优点:它比使用一个组合模型更好地分离出问题。

缺点:这个模型没有任何商业逻辑,可以吗?


我们还考虑过用某种服务在外层完全管理这些设置。

优点:没有业务逻辑的无领域模型

缺点:可能会被绑定到一个特定的框架吗?


我还缺少更多的优点/缺点吗?一种方法明显比另一种好吗?有没有一种方法我完全错过了?谢谢

您必须做出的核心决策是显示舍入是应用程序业务逻辑的一个方面,还是"只是显示的一个部分"。

如果您认为它对业务逻辑很重要,则应该使用实体对其进行建模。

如果您认为它只是"向用户展示价值"的一个方面(因此与业务规则无关(,则应将其存储在单独的存储库或服务中,然后由"展示者"应用。

[table("NameTable")]
public class Transducer
{
//Name is the ID
[Key] //is Key from table
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double RawValue { get; set; }
public double ScaledValue { get; private set; }

public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}

最新更新