为什么要避免形式继承?


9

我记得学习VB4并将一个按钮拖动到窗体上,双击该按钮,然后在刚刚被我神奇地祝福的事件处理程序中键入代码。来自QBASIC,我为“ VB”中的“ V”而感到激动,这是自切面包以来最好的视觉设计师。

当然,您可以通过编程方式完成所有这些操作,但是“ V”的魔力是如此吸引人,您只能忍不住拖动该按钮。我们被鼓励走那条路。

但是几年前,我开始学习C#和.net框架,并且对我以为我知道的一切刚刚消失的方式着迷。VB6中发生了很多神奇的事情,.net完全揭开了它的神秘面纱:以构造函数和InitializeComponents方法为例。在后者中,您将找到从工具箱中拖动的所有控件实例,已注册的所有事件以及在设计器中设置的属性。

很好...我想。只是,我感觉我不“拥有”正在发生的事情,我只能通过设计者修改的这段代码使我烦恼不已。每次将一个表示“确定”的按钮从一种形式复制到另一种形式(有时连同其兄弟“取消”)时,您实际上是在复制代码,这是一种罪过吗?教皇说,干,别重复。

除了客观存在的宗教和思想流派之外,我们是否不应该从基本表单中获取表单,并让“确定”按钮(及其所有朋友)都在基本表单上生活?像a这样的东西FormBase衍生出a DialogFormBase; 立即创建所有类...通过键入代码。根据实例的类的创建方式创建按钮(即,构造函数的enum参数确定要创建的按钮),将控件布置在拆分面板和流布局面板的内部,并按如下方式插入表单Content适用于主要内容面板。这不是ASP.net对母版页和内容占位符的作用吗?当我需要一个新的“母版页”时,我会派生一个表单,但是这个新的“母版页”仍然派生自基本表单类,因此整个应用程序的视觉效果是一致的。

对我来说,这是很多更多的代码重用比什么都重要,我曾经在的WinForms设计师做的,它甚至不是辛苦,代码不与200线方法混乱,我无法控制,我可以将评论放在我喜欢的位置,它们不会被设计师覆盖。我想这只是模式和体系结构的问题,这就是带我进入此链接的地方:能够共享通用功能的Windows窗体的最佳设计,我在那里发现,除了那里的答案,我确切地表明了我的意思。这样做,但它建议形式的继承,因为设计师的考虑。那是我不了解的部分出于代码结构方面的考虑,尤其是在形式和控件继承方面,我认为没有理由要避免,除非这样做会破坏设计人员

我们不能都只是懒惰,所以我缺少哪一部分?


我不明白 您是否暗示我们不应该使用视觉设计器并手动编写所有GUI代码?
欣快感2013年

在.NET之前,控制所有拖到窗体上的对象的代码在哪里?
JeffO

1
@JeffO从我已经处理的遗留代码来看,我会在表单上说的介于临时内联SQL和业务逻辑之间。关键是WinForms .net。因此,如果设计人员能够很好地处理当今闻起来像“不良代码”和“不良编码习惯”的气味,并且实际上在您开始构建事物时会破坏它们,那么我说放弃设计师并将其视为形式(类!)。 。,无论如何,用C#编写UI层与用ExtJS编写UI层有何不同?在WinForms中这样做很“乏味”,因为“嘿,有一个设计师”?编写ExtJS UI乏味吗?
Mathieu Guindon

我要引用另一个用户:CodeCaster; 事件处理程序旨在将GUI连接到您的业务逻辑。如果您有一个用于输入用户名的文本框和一个“添加”按钮,则单击“添加”按钮应仅调用_userRepository.AddUser(UsernameTextbox.Text)。您不需要事件处理程序中的业务逻辑。stackoverflow.com/questions/8048196/…–
Pieter B

@Pieter不会在您的表示层中放入DAL依赖吗?
Mathieu Guindon

Answers:


9

我要用不同的范式反对您:赞成继承而不是继承。

即使当您开始手动编写GUI代码并使用继承在表单之间共享行为和视觉效果时,也会遇到与普通OOP设计相同的问题。假设您有具有“确定/取消”按钮的DialogForm和具有网格的GridForm。您可以从DialogForm派生所有对话框,并可以从GridForm派生带有Grid的所有窗体。然后,您发现两者都需要形成表格。您将如何解决?如果使用表单继承,则无法解决。另一方面,如果您使用的是UserControls,则只需将GridControl放在表单上即可完成。而且您仍然可以将Designer与UserControls一起使用,因此您不必浪费时间编写繁琐的GUI代码。


好吧,基本表单只有一个固定了Panel2的SplitContainer,其中包含一个称为FlowLayoutPanel BottomPanel并承载常见的Ok / Cancel / Apply / Close行为;Panel1包含一个SplitContainer,其中Panel1固定(以承载常见的“指令”标签,或菜单,工具栏,顶部为其他内容),Panel2包含一个受保护的Panel,称为MainContent;每个实际的实现都决定如何填充它。所有内容都可以注入到实现中,是的,这可以是与设计人员一起制作的用户控件,可以节省时间,方便..但是表单本身呢?
Mathieu Guindon

这里的问题是规模。当您采用10种形式的申请时,拥有一个通用形式并不重要。当您使用数十种或数百种形式的应用程序时,问题就开始了。然后,您将拥有一些具有共同部分的表单,但是这些表单不足以创建基本表单。在这种情况下,您可能会想使用不同的布局或不同的按钮,但其他所有内容保持不变。那就是问题开始的时候。
欣快的2013年

2
如果您进行了一半的体面设计,那么“规模问题”将不存在。我们有一个项目,我在其中处理了数百种表单。我们大量使用表单继承来提供一致性和通用功能,而且从未遇到任何问题用它。
梅森惠勒

2
@MasonWheeler我的经历恰恰相反。我们试图在我们的一个应用程序中使用表单继承,并且每当我们对基本表单进行很小的更改时,整个事情就崩溃了,我们不得不手动修复所有其他表单。另外,当您处理继承的表单时,设计师的行为很奇怪。
欣快感2013年

1
@Euphoric:哪个设计师?我们使用Delphi,它的设计器可以很好地处理继承的表单。再说一次,如果您拥有良好的设计,就不会遇到这些问题。如果您不计划任何事情,那么一旦碰到它,一切都会变得很脆弱并且会破裂,但这与任何其他代码都没有什么不同。
梅森惠勒

2

其中大部分与选择的技术堆栈有关。

WinForms和WPF都可以是.NET UI框架,但是在实现最终目标的方式上差异很大。某些范例在各种技术之间可以很好地移动,而其他范例则不能,您不应该仅仅因为您认为它存在于每个框架中就尝试强制使用范例。MVVM适用于WPF / SL是有原因的,而MVC是ASP.NET中与WebForms等不同的概念。某些技术在某些范式下效果更好。

请记住,生成的代码通常应从DRY问题中删除。尽管在某些情况下适用,但通常应该忽略它。当然,DRY概念应该仍然是Presentation层之外的焦点,但是在Presentation层,生成的代码通常不是您正在使用的框架的副产品。这并不是说您不能在方法中应用DRY原理,而是要保留谨慎。您可以创建一个基本表单并无限期地继承它吗?是。是否可以根据需要每次将组件拖放到新窗体上?是。始终专注于最终目标,避免潜在的缺陷,使其易于在下游重构,并具有可扩展性,同时在所选技术范围内工作。


0

可以使用继承来提供正确的封装字段并进行相应填充。如果您热衷于使用继承,我的建议是拥有基本形式和该形式的相应模型,并为每个派生导出形式和模型。

一种更好的选择是将相关控件分组为一个或多个UserControl控件。您只需要一点逻辑就可以将相关数据放入其中。


0

我完全同意梅森·惠勒的观点,尽管三年来甚至他本人都改变了主意。

我正在尝试寻找从Delphi可执行文件迁移到WEB的替代方法。

到目前为止,我决定使用UNIGUI,因为我仍然可以使用表单继承。我希望Delphi拥有Dart之类的Mixins,因为这会让我少一些祖先。但是我觉得人们用MVC编写的代码比使用Visual Form Inheritance编写的代码要多得多,因为大多数导航,对数据模块中的验证规则的调用(applyupdates),sql过滤条件,搜索客户端数据集,所有内容均以5或6编写祖先。

即使是“有了MVC,您也可以更轻松地将Delphi留在Feature中”对我来说也不起作用,因为人们邀请OOP,所以一切都是类,属性,方法。所以我需要的只是一个翻译。确实找不到任何优势,也许对于那些不那么复杂但每日更改的网站而言。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.