【问题标题】:What is an appropriate MVC-based OOP design for my case?什么是适合我的案例的基于 MVC 的 OOP 设计?
【发布时间】:2021-12-04 21:01:12
【问题描述】:

假设以下基线设计:我有一个类CarElement,它包含与汽车的视觉表示和数据模型/逻辑表示相关的属性和方法:

class carElement
{

    // UI related properties and methods:
    public Size DrawSize { get; set; }
    public Point Location { get; set; }

    public void Draw()
    {
        // do something...
    }

    // data model / logic related properties and methods:
    public double weight { get; set; }
    public string manufacturer { get; set; }

    public double CalculatePrice()
    {
        // do something...
        return 0;
    }
}

这个类的用法如下:carElement的多个实例被绘制到某个画布上。单击每辆绘制的汽车,使用propertygrid.SelectedObject = InstanceOfcarElement 在属性网格中显示该汽车的属性。

在我看来,这种设计是有缺陷的,因为数据模型和视觉表示在类设计中没有分开。我想改进 MVC 的设计,我正在寻求有关良好设计决策的建议。

我目前对此的看法是将上面的类 carElement 分成类似以下两个类。

class carUIElement // organizes visual representation of a car
{
    public Size DrawSize { get; set; }
    public Point Location { get; set; }

    private carDataElement linkedCarDataElement;

    public void Draw()
    {
        // do something...
    }

}

class carDataElement // organizes data model organization of a car
{   

    public double weight { get; set; }
    public string manufacturer { get; set; }

    private carUIElement linkedCarUIElement;

    public double CalculatePrice()
    {
        // do something...
        return 0;
    }
}

使用这种方法,我不清楚以下几点:

  • carUIElement 应该知道它所链接的 carDataElement,反之亦然。有没有比上面代码中的简单链接更好的设计方法?
  • 当点击绘制的 UIElement 时,如何最好地在属性 Grid 上显示 UI 和数据模型属性

整体方法可行吗?以上开放点呢?我错过了判断这一点的经验,所以我会感谢你的 cmets。谢谢。

【问题讨论】:

  • MVC 与此示例中的关注点分离无关。我不认为 WinForms PropertyGrid 是模型、视图或控制器中的任何一个的示例。
  • "CarUIElement 应该知道它所链接的 CarDataElement,反之亦然。" - 这是不正确的:虽然CarUIElement 一定需要了解CarDataElement,但反之则不然:CarDataElement 不应该关心它是如何呈现的,因此CarDataElement 不需要引用任何@987654336 @。此外,您应该确保您的类型永远不会处于无效状态:您的构造函数应该始终将对象初始化为有效状态(因此在适当的情况下使用 ctor 参数和 readonly 字段/属性)。
  • “当单击绘制的 UIElement 时,我如何最好地在属性 Grid 上显示 UI 和数据模型属性” - 不幸的是,由于 PropertyGrid 的限制(以及 C# 缺乏真正的 mixins)你需要一个 third 类,它结合了 both 类型(CarUIElementCarDataElement )的所有可变属性,onlyPropertyGrid。或者......为什么不拥有两个属性网格?
  • 感谢 cmets。我同意你的第二条评论。关于第一个:如果我的问题在严格的软件设计方面不是真正的 MVC,那么请接受我的道歉并忍受我,因为计算机科学不是我的主要教育。

标签: c# oop model-view-controller class-design propertygrid


【解决方案1】:

虽然我们应该始终注意不要过度智能化,但毕竟我们作为程序员比艺术家更像是泥瓦匠,即使圣母教堂只是一个建筑而不是艺术,也不总是需要过高的装饰和隔音室,假设下一个版本会和上一个一样宏伟:)

我是什么意思?我建议使用 MVC 的实用主义,因此如果在程序的早期阶段,它可以具有与逻辑模型相同的 ui 模型,有时也称为数据传输对象,这本身不是反模式 imo。 显然,一旦构建了 ui,我们就开始发布带有假定结构的实例,当它开始限制产品的开发时,它是如何呈现的,通常是当您需要比 ui 相关的更多信息时,存储在实体上,那么您可以通过创建 DTO 模型对象来锁定界面,并使用初始模型进行派对。 所以我知道你要去哪里以及为什么你可能想要分开它。

然后我们经常有 Web 前端,尤其是使用 mvc,然后大多数情况下它将不再是数据绑定视图,而是像 Angular、React、Vue 甚至 Blazor 这样的 MVVM 东西,如果出于某种原因你可能想要的话,或者传统的 Razor 页面,真的吗?在新的发展?? 如果只有序列化的 JSON 版本可用于您的视图引擎,我尽量不在 DTO 类中放置任何可能丢失的内容。这样当现代化发生时,您的控制器/ api 基本上不必改变。

因此,单独的单独类涉及数据访问或传输类中的无逻辑,我的建议将类似于以下内容,但最终会遇到您的问题:

a) 如果您使用它来加载数据模型中的导航属性,例如使用实体框架,那么它是必需的。 在您的 UI 类型中,频率是关键,通常我们喜欢将所有数据推送到点中,这样它们就不需要执行其他任何操作,但是如果该类正在被序列化和反序列化并且您使用像 AutoMapper 这样的工具来移动到并且,如果您在像 WPF 这样的 Windows 客户端中,嘿,您的模型已经在客户端上并且已经为 MVVM 加载,那么您处于一个更好的地方,以至于您可能不会真正关心前端类型,直到他们需要改变。

b) 问题是您是否总是想同时显示两者,或者您是否可以隐藏 cardata 元素直到他们要求它,这将决定让 DTO 包含关系中的数据或仅包含外键和imo 有一个额外的查找方法可用。

所以建议简介:

/// <summary>
/// Drawing is a separate concern of the application
/// </summary>
class DrawManager
{
    public void DrawCar(CarBase car) { }
}

/// <summary>
/// So is calculating prices
/// </summary>
class PriceManager
{
    decimal CalculateCarPrice(CarBase car) { throw new NotImplementedException(); }
}

/// <summary>
/// The 2 classes share properties, invent a base class to abide by the DRY principle
/// </summary>
class CarBase
{
    public Size DrawSize { get; set; }
    public Point Location { get; set; }
}

/// <summary>
/// Now they are identical
/// </summary>
class carElement : CarBase
{
    carDataElement CarData { get; set; }
}

/// <summary>
/// Now they are identical
/// </summary>
class carUIElement : CarBase
{
    carDataElement linkedCarDataElement;
}

/// <summary>
/// The data about a car, in RDBMS typically normalized into a seperate entity like you have,
/// does UI really need any of them? Is it always needed when other members are accessed? 
/// </summary>
/// <remarks>
/// we could choose to have the data model have a navigation property and then let the ui member not have it and give it a method to ackquire it,
/// but then that shouldn't get done to early and well if it always needs it, it is not yet a seperate datatype justification for the ui aspect
/// </remarks>
class carDataElement
{
    public double weight { get; set; }
    public string manufacturer { get; set; }
}

【讨论】:

  • 感谢您的意见!我会尝试继续您的建议。
猜你喜欢
  • 2020-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多