【问题标题】:Configurable Display Properties for Domain Models域模型的可配置显示属性
【发布时间】:2019-04-12 08:23:24
【问题描述】:

使用 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
} 

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

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


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

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

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


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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    【讨论】:

    • 第一个案例对我来说很有意义。添加到示例中,我可以预见需要同时显示舍入值和非舍入值。在这种情况下,我认为让业务逻辑包含两个值并让应用程序/显示层选择使用哪个值是有意义的,你同意吗? 如果您认为它只是“向用户展示价值”的一个方面,它应该存储在单独的存储库或服务中,然后由“展示者”应用。 如果就业务需求而言,舍入值无关紧要?
    • 是的。换句话说:如果只需要舍入以使值在 UI 中看起来漂亮且格式正确,则将舍入配置分开并让演示者/视图模型应用它。
    【解决方案2】:
    [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;
        }
    
    }
    

    【讨论】:

    • 问题是关于DisplayRounding 属性,而不是Name
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    • 2019-08-10
    • 2018-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多