1

我有一个表格和一个逻辑类。基于用户操作,该类生成操作列表。然后这些操作需要在表单上显示为按钮,以便用户可以从中进行选择。我最初的解决方案是这样的:

public class Logic {
    public List<string> GetActions() {
        List<string> result = new List<string>();
        // ...prepare list
        return result;
    }
}

public class FrmGUI : Form {
    Logic logic = new Logic();
    private void PopulateButtons() {
        foreach(string action in logic.GetActions(){
            //...create button
        }
    }
}

GUI 从 Logic 类中检索字符串列表,然后使用它来填充带有按钮的面板。现在据说这是不好的 OO 实践,因为我正在公开有关 Logic 类的行为方式的一些内容。这里假设 GetActions 方法将始终存在并且 Logic 类将始终能够返回此字符串列表。

另一个解决方案是:

public class Logic {
    public void PopulateButtons(Panel panel, Action<object, EventArgs> eventHandler) {
        // ...prepare list
        // ...populate buttons
    }
}

public class FrmGUI : Form {
    Logic logic = new Logic();
    private void PopulateButtons() {
        logic.PopulateButtons(this.panel1, actionButtonClickHandler);
    }
}

现在,GUI 类对逻辑类一无所知,只希望填充按钮。另一方面,逻辑类现在涉及到 GUI 的东西。

处理此类情况的正确方法是什么。或者是否有第三个更好的实现。

4

6 回答 6

2

我会使用前一种模式:逻辑层创建信息,而 UI 层使用该信息来创建 UI。

这样,如果您决定重新设计 UI 以使用下拉列表项,您只需更改 UI 层,而不是逻辑。

这意味着 UI 层对逻辑层提供的类型/数据的依赖最小(只要它不知道逻辑是如何实现的就可以了),但逻辑层对此一无所知关于 UI 实现是什么——这就是你想要的(系统中的低级组件不应该对高级设计一无所知,而高级组件必须对它们使用的低级组件有基本的了解)。

最好是应用程序(或其他一些外部实体)创建逻辑和 UI 并将它们链接在一起,而不是 UI 本身创建逻辑 - 这将有助于 UI 和逻辑更加松散耦合。

于 2012-09-14T11:42:45.360 回答
1

Logic可以报告它支持的操作(第一种模式)对我来说看起来不错(但返回类型GetActions真的应该是IEnumerable<string>而不是列表)。

不好的是,在您的示例中,表单Logic直接实例化了该类。Logic通常,您会为您可能拥有的不同类型的类创建一个接口或抽象基类,并让具体的实现填充功能。然后表单将通过一些控制反转机制获得要使用的逻辑。

于 2012-09-14T11:41:55.393 回答
1

正确的?????多年来,很多人投入了大量时间来尝试标准化这种方法,恐怕答案可以从那里的 ui 设计模式的数量中推断出来!

您可能想查看 MVC、MVP、MVVM 模式,所有这些模式目前都很流行。

一般来说:

尝试将逻辑与演示分开是个好主意,这样你就走对了。但是请记住,这种拆分的后果之一是,您的“逻辑”最好不要对演示文稿一无所知(因为您已经有一个负责该问题的类)。

因此,您可能想考虑“按钮”的概念,并考虑(从您的逻辑角度来看)“我真的不是指命令吗?”。当您在屏幕的上下文中考虑它们时,它们才真正成为按钮。但是,比如说,在特定银行账户上加载交易的命令......你不需要一个屏幕来概念化它是如何工作的。

我发现的一件好事是想象你要开发这个应用程序,它既有表单前端,也有做同样事情的网络前端。显然,这两个应用程序将具有完全不同的表示层,因为所涉及的技术根本不同。

但是因为您不想编写两次代码,所以您也将拥有一个“逻辑”层,在那里您将尽可能多地填充通用代码。例如,决定一个银行账户是否透支——不管你是网络还是赢,透支仍然是透支。相反,您最终在 web 和 win 之间编写不同代码的任何地方都属于您的“表示”层。例如,以红色显示透支余额。

深思熟虑。

于 2012-09-14T11:57:15.703 回答
1

我建议在你的Logic和你的FrmGUI.

对于一个简单的示例,假设您在应用程序中有一个登录名。为您的逻辑屏幕定义一个界面。请注意,这里没有提及使用了哪些控件。逻辑类永远不知道使用的 UI 类/表单。

interface ILoginScreen : IScreen
{
   event EventHandler LoginInvoked;
   event EventHandler CancelInvoked;

   string User { get; set; }
   string Password { get; set; }   
}

在您的 LoginLogic 类中,您有如下代码:

void Start() // initial LoginLogic method
{

   ILoginScreen loginScreen = uiFactory.CreateLoginScreen();

   loginScreen.User = string.empty;
   loginScreen.Password = string.empty;

   loginScreen.LoginInvoked += new EventHandler(LoginScreen_LoginInvoked);
   loginScreen.CancelInvoked += new EventHandler(LoginScreen_CancelInvoked);

   loginScreen.Show();

}

void LoginScreen_LoginInvoked(s, e)
{
   if (ValidateCredentials(loginScreen.User, loginScreen.Password))
   {
      // goto the next screen logic controller
   }
}

在您的表单中,您实现 ILoginScreen 并使用来自 USer 和 Password 属性的数据刷新 UI 字段。此外,您会根据用户反馈(按钮单击、Escape 击键等)引发所需的 Login 和 Cancel 事件。

虽然这是一个简单的示例,但我做了很多 Windows Mobile 和 Windows CE 应用程序,在这些应用程序中,希望在外形尺寸迥异的操作系统变体上运行相同的应用程序是很常见的,这种方法让您可以真正掌握新的 GUI 形式-因素。该用法的核心是动态加载的 UIFactory 以提供适当的 UI 实现。

于 2012-09-14T17:58:51.057 回答
0

第一个更好,因为您在 GUI 和逻辑之间的接口只是一个字符串列表。之后,这一切都取决于您从按钮调用逻辑类操作的方式。如果您有一个采用操作字符串的通用方法,那很好。如果您需要根据操作字符串在逻辑类上调用不同的方法,则需要在 GUI 类中进行映射以映射操作字符串和方法调用。您还可以从您的逻辑类中导入此“操作字符串 - 映射方法”以保持分离。

于 2012-09-14T11:44:50.747 回答
0

我的观点是,这取决于创建逻辑层和 GUI 层之类的东西的原因。我认为最常见的原因是重用逻辑,例如将其用于 WPF 和 Web GUI,或者必须在将数据发送到 GUI 之前对其进行处理。您的第一个示例符合上述模式。在您的第二个示例中,逻辑似乎不可重用,因为它是特定于 gui 的。然而,在现实世界中存在正确或错误的答案。该架构应该满足您的需求并使您的项目可维护(例如通过减少冗余代码)。就您而言,问题是:您多久需要一次这些功能以及何时/何地需要它们?

于 2012-09-14T12:05:17.617 回答