UI 开发模式

一个团队中,界面程序员是个尴尬的角色。一般情况下,他们只是排列不同的控件,然后将美工提交的图片放置于窗体的某个位置…… 真的这么简单吗?我们在强调代码重用和组件化的时候,似乎有意无意忽略了界面的重用型和可维护性,一不小心这个原本看似简单的工作就有可能对项目组造成损害。

我们来看看界面开发中常见的问题,并试图以我个人的经验给出一个可能是“合适”的解答。

1. 稍微复杂的窗体上被密密麻麻放置了一堆控件,我们要调整界面时不得不从N多的名称中去寻找,而且还得小心控件的叠放层次,因为稍不小心,就会引起一堆麻烦。这好比在荆棘林中摘沙枣,苦痛不堪。

在OO世界,一切皆对象,只不过我们将这些对象堆在了一起,原本的有序变成了无序。其实解决方法很简单:

第一,复杂的窗体往往可以划分为几个不同的功能块,我们将每个功能块封装为一个组合控件(C# UserControl),此组合控件对窗体公开一些操作接口即可。如此一来,我们的窗体上只有几个自定义控件,自然要清爽很多。每个组合控件内,由于其功能的相对单纯,自然也好维护了。最重要的是我们同时将窗体中错综复杂的UI代码分散到多个组合控件类中,对于代码维护也有不小的好处。

第二,组合控件的使用,还有利于重用。我们很多窗体都有可能使用某一个组合控件。

2. 程序中不可避免地要进行窗体间的相互调用,Form1调用Form2,修改Form2.Button1.Text,然后又new Form3().ShowDialog()……,晕。

这样的UI代码无处不在,我们要调整某个窗体,就要修改无数个地方,错误也不期而至。这样的情形好比一个例子,每个窗体都是一件衣服,我们试图用不同的上衣、裤子、围巾去打扮出一个漂亮的形象,结果由于相互调用,造成了所有的衣服被缝在了一起,要么没法穿上身,要么脱不下来,更别奢望用别的上衣来进行重新搭配,结果是上剪下补,人仰马翻,到处是窟窿,好好的衣服给毁了。

问题出在哪呢?很简单,目标错误。无论是上衣,还是裤子,他们依附的是穿衣人的躯体,由躯体来决定不同衣服的搭配,由躯体去调整不同衣服的关系和位置,衣服之间并没有直接的关联。那么具体要怎么做呢?同样简单,为我们的窗体制造一个躯体—— FormHelper,所有的窗体都通过FormHelper来获得其它窗体的调用接口。
  public class Form1 : Form
  {
    public void Form_Load()
    {
      new Form2().Execute();
    }
  }

  public class Form2 : Form
  {
    public void Execute()
    {
      if (form1.Tag == null)
        MessageBox("YES");
      else
        MessageBox("NO");
    }
  }

上面这段代码中,由于Form1和Form2的相互调用,造成了我们前面所说的坏味道,那么我们接下来,赋予它们一个躯体,来解决耦合问题。
  public class Form1 : Form
  {
    public void Form_Load()
    {
      FormHelper.Form2Execute();
    }
  }

  public class Form2 : Form
  {
    public void Execute()
    {
      if (FormHelper.Form1Tag == null)
        MessageBox("YES");
      else
        MessageBox("NO");
    }
  }

  public sealed class FormHelper
  {
    public static void Form2Execute()
    {
      new Form2().Execute();
    }

    public static object Form1Tag
    {
      get { return form1.Tag; }
    }
  }

如此一来,窗体间的耦合被解除,每个窗体的变更只需要调整FormHelper中相关的方法即可。额外的好处是,当窗体被赋予多个人开发时,我们无需等待其他人完成工作,无需知道其他窗体的名称和类型,只需给FormHelper提供一个模拟目标就可以开始我们自己的工作,代码合并时,修改一下FormHelper中的相关方法即可完成替换。当然这个例子是不完善的,仅仅用来表达我想说的意图。在设计模式中对此称之为“中介者”模式。

3. 在窗体开发中还存在另外一个问题就是UI代码和算法被放置在一个类中。

我个人非常反对这样做,窗体类要做的只是窗体展示和操作事件触发,而不该包含任何算法内容。比如在某个窗体中要根据一些条件来动态生成一些不同的TagPage,我们这个生成算法应该从窗体类中脱离出来,放置于FormEx类中,使其和窗体设计各自独立变更。在窗体类中的代码尽可能做到简单、精练。

这篇帖子要表达的不是纯粹的技术问题,而是个人总结的一些习惯和原则,这些原则从某种程度上解决了我以往遇到的问题,也希望对于阅读者有一定的启发和帮助。  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值