2

您是否曾经根据您的用户界面部分构建您的源代码?例如,如果您的 UI 包含:

  1. 用于显示一些属性的 GridView
  2. 3D 渲染面板
  3. 用于选择活动工具的面板

,然后您或多或少地按以下方式命名和分组您的变量和函数:

class Application
{
  string   PropertiesPanel_dataFile;
  DataSet  PropertiesPanel_dataSet;
  string[] PropertiesPanel_dataIdColumn;
  void     PropertiesPanel_OpenXml();
  void     PropertiesPanel_UpdateGridView();

  string   ThreeDView_modelFile;
  Panel    ThreeDView_panel;
  PointF[] ThreeDView_objectLocations;
  void     ThreeDView_RenderView();

  string   ToolPanel_configurationFile;
  Button[] ToolPanel_buttons;
  void     ToolPanel_CreateButtons();
}

您对此有何看法?这种架构可以长期工作吗?

PS。尽管此解决方案可能会让您想起 Front-ahead-design 愚人节的笑话http://thedailywtf.com/Articles/FrontAhead-Design.aspx我的问题是严肃的。

编辑

半年以来一直在维护和扩展这种代码。应用程序在主 .cs 文件中已增长到 3000 多行,大约 2000 行分散到较小的文件中(包含通用帮助函数和类)。代码的许多部分应该被概括并从主文件中取出,我一直在努力,但最终这并不重要。代码的结构和细分非常简单,通过它很容易导航。由于 UI 包含的主要组件少于 7 个,因此将整个设计一次融入您的脑海中没有问题。回到这段代码总是令人愉快的(在一些休息之后)并立即知道从哪里开始。

我想这个巨大的类似程序的结构在我的案例中起作用的原因之一是 c# 中 UI 编程的类似事件的性质。在大多数情况下,这些代码所做的就是实现不同类型的事件,这些事件确实特定于这个项目。尽管某些事件函数会立即变成几页长的怪物,但事件处理程序之间的耦合并不是那么紧密,因此之后重构和压缩它们变得更容易。这就是为什么我故意将泛化和重构留到以后,当其他项目开始需要该项目使用的相同部分的实现时。

PS 可以浏览 3000 行代码,我在 Visual Studio 中使用 FindNextSelection- 和 FindPrevSelection-macros。左键单击某个变量后,我按 F4 跳转到它的下一个实例,按 F2 跳转到前一个实例。也可以选择变量名称的一部分并在部分名称匹配之间跳转。如果没有这些捷径,我很早就会迷失方向:)

4

3 回答 3

1

这在概念上看起来非常程序化,并且完全绕过了 OOD 的价值。明智的方法是为您的每个元素创建对象,您给出的值将是这些对象的属性,即

class PropertiesPanel 
{
  public string DataFile { get; set; }
  public DataSet DataSet { get; set; }
  public string[] DataIDColumn { get; set; }
  etc...

我想你明白了,所以我不打算把全部都打出来。这是第一阶段,您可能需要做进一步的工作来适当地构建您的应用程序。

我收到的关于 OOD 的最佳建议是查看应用程序的每个逻辑分支都可以提取到的最小对象,它可能具有属性的本机类型(对于 .NET,重新发明框架对象也没有意义,因此它们可以在你的基类中),然后使用继承、多态性和封装来扩展这些基类,直到你有一个封装逻辑分支的对象。

当时我正在编写一个将数据推送到 I2C 设备的应用程序,所以我从一个将位放入 I2C 总线的类开始,该类由将字节放入总线的类继承,由将字节放入总线的类继承一个字节数组到总线上,最后是一个放置地址和字节数组的类。这是相当极端的OOD,但它产生了非常干净的代码,每个类都非常小并且非常易于调试。

在考虑问题时可能需要更多的工作,但从长远来看,它可以节省很多时间,这并不好笑。

于 2009-06-06T08:41:43.770 回答
0

可以根据你的 UI 部分来构造你的用户界面代码,但是你的程序的非 UI 相关的逻辑应该分开。

但是 UI 部分的事件你不应该只是把所有东西都归为一类。相反,您应该将您的 UI 代码分成几个类,以便每个类只处理一个 UI 组件,而不处理它不需要知道的其他组件:

类应用
{
  属性面板
  三维视图
  工具面板
}

类属性面板 {
  字符串数据文件;
  数据集数据集;
  字符串[] 数据标识列;
  无效的 OpenXml();
  无效更新网格视图();
}

类 ThreeDView {
  字符串模型文件;
  面板面板;
  PointF[] 对象位置;
  无效渲染视图();
}

类工具面板 {
  字符串配置文件;
  按钮[] 按钮;
  无效创建按钮();
}
于 2009-06-06T08:42:26.937 回答
0

您对此有何看法?

一团糟。

这种架构可以长期工作吗?

不。(至少不是没有很多汗水。)

这些名字非常冗长。如果您考虑一下,长名称前缀的存在是为了创建一种单独的“命名空间”,将相关的事物组合在一起。对于这种东西,已经有一个更好的语言结构——它是classes。但主要问题在其他地方。

用户界面经常改变,概念很少改变。如果您的代码结构反映了用户界面,那么您将被锁定到这个特定的界面。这使得重用和重构代码非常困难。如果您围绕问题域中的基本概念构建代码,您就有更好的机会在软件开发时重用现有代码——设计将适应变化。变化总是发生在软件中

(我希望“问题域中的基本概念”部分清楚。例如,如果您为当地剧院创建系统,您应该将您的设计基于电影、访客、座位等概念,而不是围绕 MovieList、SeatMap、TheatrePlan 等来构建它。)

大多数时候,尽可能将核心代码与 GUI 分离是一个好主意(这正是模型-视图-控制器设计系统的全部内容。)这不是学术练习,也不仅仅是如果界面要更改,则需要。将 GUI 与其余代码分离的一个很好的例子是 Mac OS X 上的 GUI 编程,带有界面设计器、绑定等。不幸的是,它需要一段时间才能进入,您不能简单地浏览网络上的文档并获得启发。

于 2009-06-06T08:55:19.687 回答