3

我有一个软件设计问题。假设我有一个包含一些元素的 Windows 窗体,并且我有一个客户对象。例如,客户可以是企业、私人或公司。

现在,表格中将要发生的所有决定都将取决于客户类型。例如,某些元素将被隐藏,某些标签文本会有所不同,等等......事件将有不同的响应。

显然,一种编码方式是在每次需要做出决定时使用 CASE 语句。另一种方法是从基类继承一个 Customer 类和 3 个其他类,例如 BusinessCustomer、PrivateCustomer 和 CorporateCustomer。在后者中,就会出现一个问题:您将如何将窗户合并到其中......

已编辑

我有一个想法:我可以在表单中嵌入表单吗?我的要求并没有规定同时显示两个窗口,所以我不必使用 MDI。但是为了根据这里的一些 ppl 评论简化我的设计,我想维护 3 个不同的客户表单,并动态嵌入到主表单中。这样,三个 GUI 是分开的,我不必处理每个控件的可见性。

我假设我可以将一个表单添加到另一个表单,例如:

Form child_form = new Form();
parent_form.Controls.Add(child_form);
4

6 回答 6

2

这些决定真的不应该在 GUI 中做出。你应该在你的 GUI 后面有一个 ViewModel 来做出这些决定,并为它编写单元测试。(或者一个 Presenter,或者一个 Controller——不同的名字都意味着大致相同的东西:把决定从 GUI 类中取出,放到你可以单元测试的东西中。)

然后,您的 ViewModel 将具有例如 GUI 将禁用的每个元素的布尔属性,以及您可以采取的每个操作的方法(CloseCustomerAccount() 或其他)。

只要表单是为特定类型的客户创建的,并且客户在表单的生命周期内不会更改为不同类型的客户,您就可以传递您的客户对象(存储所有实际客户数据) 到 ViewModel 的构造函数,然后将 ViewModel 传递给 Form 的构造函数。窗体可以在调用 InitializeComponent() 后立即设置其所有 Enabled 属性。另一方面,如果客户类型可能发生变化,那么您的 ViewModel 需要公开一些事件以供表单挂钩,以便表单知道何时重新运行其启用逻辑。

然后,您的问题将移出 Form 并进入 ViewModel。你有一个 ViewModel 类和一堆 case 语句,还是三个 ViewModel 类(可能有第四个是基类)使用多态性,还有一个工厂方法根据特定客户决定要实例化哪个 ViewModel 类?

我会让你的代码成为那里的指南。从最简单的方法开始,这可能是案例陈述。为你关心的每一个行为写一个单元测试。如果 case 语句开始变得太笨拙,则为每个客户类型添加一个 ViewModel 后代,并开始将 case 语句提取到虚拟方法中。如果你在重构过程中犯了错误,你的测试会抓住你。

于 2009-04-29T22:39:03.747 回答
1

如果您确实有 3 个不同的窗口,每个窗口都处理特定类型的客户,那么使用基类或合同就没有多大意义了。尽管工厂类接受客户类并确定要使用的正确屏幕,但您可能会很聪明。

我遇到了很多。我最终得到一个处理通用内容的基本窗口,然后为每个具体类型扩展它。

于 2009-04-29T22:22:26.033 回答
1

我同意 Joshua Belden 的回答。为不同类型的客户提供三种不同的表格可能是最容易维护的。

此外,如果您还不知道,您可以从 Form 类派生并在派生的 Form 类中对其进行调整。这甚至得到了设计师的支持。

但是,我想提供一个替代方案:

桥接模式:将抽象与其实现分开,因此两者可以独立变化。

可以做的是:

创建三个单独的UIImplementation类。这些类可以调整 UI 和Customer表单的事件。为了访问表单的私有成员,您需要将UIImplementation类声明为嵌套在CustomerForm类中。(使用部分类将它们分成不同的文件)。如果表单本身很重要,并且调整微不足道,这可能是一个不错的选择。很难说。

于 2009-04-29T22:57:03.673 回答
0

只需选择实现一些抽象客户接口的三个类。在您的应用程序中,您将有一个客户类型的变量客户,并且特定客户类型的对象将存储在那里。然后,您的 GUI 可以仅依赖接口并调用客户变量上的方法,而不管客户实际与 GUI 交互的是什么。

看看这篇文章

于 2009-04-29T22:23:28.403 回答
0

我将采用 MVP 类型方法并定义 CustomerPresenter 类,该类公开一个布尔属性,该属性将通过绑定派生您的 UI 控件的启用/禁用状态。

public class CustomerPresenter
{
  private Customer _customer;

  public CustomerPresenter(Customer customer)
  {
    _customer = customer;        
  }

  public bool EnableUI
  {
     get
     {
       //TODO: put your customer type basic logic here (switch statement or if/else)
       return _customer.Type == CustomerType.Business;
     }
  } 
}

public CustomerForm: WinForm
{
   private CustomerPresenter _customerPresenter;

   public CustomerForm(){};

   public CustomerForm(Customer customer)
   {
      _customerPresenter = new CustomerPresenter(customer);
   }      

   private void CustomerForm_Load(object sender, EventArgs e)
   {
      _someButton.DataBindings.Add("Enabled",_customerPresenter,"EnableUI");
   }

} 
于 2009-04-29T22:54:00.123 回答
0

解决方案应该由数据驱动,而不是你的代码。

因此,如果您将各种控件标记为在状态“A”、“B”或“C”中可见,则单个方法可以查看其状态并知道哪些控件使可见或不可见。

您知道在为状态“D”添加新控件时您做对了,除了添加控件本身所需的代码更改之外,不需要更改任何代码。

您还可以考虑将表单分解为 4 个子表单、共享、子表单 a、子 b,然后在父表单上同时显示“共享”和“子 a”...

于 2009-04-29T23:01:34.677 回答