域模型的可配置显示属性

时间:2018-11-08 18:50:36

标签: c# dns domain-driven-design dto clean-architecture

使用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显示的“小数位数” Transducer基于身份。所以带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
} 

优点:比起使用一个组合模型,它可以更好地分离出关注点。

缺点:该模型没有任何业务逻辑,可以吗?


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

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

缺点:可能会绑定到特定框架吗?


我还缺少其他优点/缺点吗?一种方法明显优于另一种方法吗?有没有我完全错过的方法?谢谢!

2 个答案:

答案 0 :(得分:1)

您必须做出的中心决定是显示舍入是应用程序业务逻辑的一个方面还是“仅仅是显示的一个方面”。

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

如果您将其视为“向用户呈现值”的一个方面(因此与业务规则无关),则应将其存储在单独的存储库或服务中,然后由“呈现者”应用。

答案 1 :(得分:0)

[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;
    }

}