我有一个winforms应用程序,我没有遵循任何设计模式。我的问题是,我有这些基类包含我的所有业务逻辑。当发生异常或我需要向用户显示对话框时,我已将代码直接写入我需要它的基类中。
我知道我需要将业务逻辑和显示逻辑分开,所以我编写了一个静态类,其中包含了显示消息所需的方法。
我的问题是,是否有更简单的方法将业务逻辑与显示分开?
我的静态方法看起来像这样,
public static void DisplayMessage(string message)
{
MessageBox.Show(message);
}
public static bool DisplayDialogBox(string message,string caption )
{
DialogResult newresult = new DialogResult();
newresult = MessageBox.Show(message,caption,MessageBoxButtons.OKCancel);
if (newresult == DialogResult.OK)
{
return true;
}
else
{
return false;
}
所以我将从基类调用这些方法,比如
MsgDisplay.DisplayMessage(e.Message);
这种方法是一种很好的做法吗?
答案 0 :(得分:2)
不,这种方法不是一个好习惯。您的类和MessageBox类之间没有任何区别 请与您的班级见:
MsgDisplay.DisplayMessage(e.Message);
并且只使用MessageBox
MessageBox.Show(e.Message);
此包装器不提供任何其他功能 如果要分离业务逻辑和ui,则必须分解方法并仅在UI层中显示消息 而且,小点。而不是:
if (newresult == DialogResult.OK)
{
return true;
}
else
{
return false;
}
只输入:
return newresult==DialogResult.OK
<强>更新强> 如果要显示的只是异常消息,那么您应该捕获异常并在UI层上显示消息。因此,在您的业务类中,而不是显示消息:
void foo() {
try {
//some code here
}
catch(FooException fe) {
MessageBox.Show(fe.Message);
}
}
将异常抛出到ui层:
void foo() {
try {
//...
}
catch(FooException fe) {
//throw new BarException("Error occured: "+fe.Message); //if you want to customize error message.
throw; //If you don't need to change the message consider to not catch exception at all
}
}
然后在业务逻辑之外显示消息:
void fooButton_Click(object sender, EventArgs args) {
try {
fooBusinessClass.foo();
} catch(FooException fe) {
//if(MessageBox.Show(fe.Message)==DialogResult.OK) fooBusinessClass.continuefoo(); //if you have several options
MessageBox.Show(fe.Message);
}
}
答案 1 :(得分:2)
我通常创建一个IView
接口,然后将其注入业务逻辑类。如果逻辑“有问题”需要获得用户输入,那么它将如下所示:
interface IView
{
bool AskUser(string question);
}
class SomeClass
{
IView _View;
public SomeClass(IView view)
{
_View = view;
}
public void SomeLogic()
{
if (someCondition && !_View.AskUser("continue?"))
return;
}
}
然后您的表单可以实现IView
通过消息框提示询问用户。对于单元测试,您可以模拟静态设计案例中无法实际执行的视图。
答案 2 :(得分:2)
它比你想象的更容易在WinForms中实现一个简单的MVC-ish设计模式,你可以将其固定到现有代码上而无需进行重大修改。让表单或控件实现一个视图界面,并将视图传递给实现业务逻辑的类:
public interface IPersonDetailsView
{
bool PromptUser(string message, string caption);
}
// Your form:
public partial class PersonDetailsForm : Form, IPersonDetailsView
{
//...
public bool PromptUser(string message, string caption) {
var result = MessageBox.Show(message, caption, MessageBoxButtons.OkCancel);
return result == DialogResult.Ok;
}
}
// Your business logic:
public class PersonDetailsController {
public IPersonDetailsView View { get; set; }
public void DoingSomething() {
// ...
if (this.View.PromptUser(message, caption)) { ...
}
}
}
创建表单时将PersonDetailsController.View
设置为表单。如果您需要表单能够与控制器对话,您只需添加PersonDetailsForm.Controller
并让表单在控制器上调用公共方法。
我不会仅仅使用表单作为WinForms调用的代理,而是使用BDD方法,而不是View.ShowPrompt("Do you want to delete this person?", "Deleting person")
我会选择像View.AskUserIfTheyWantToDeleteThePerson()
这样的东西(没有参数)。这是一个很长的方法名称,但它非常明确,将实现和消息留给视图,从长远来看可以使事情更清晰。
答案 3 :(得分:1)
通常,业务层返回错误字符串。该字符串由GUI显示在MessageBox或状态栏中。
顺便说一句,您可以从消息框中获取结果(您不需要对话框):
MessageBoxResult MBR = MessageBox.Show("Click Me", "Title", MessageBoxButton.YesNoCancel);
MessageBox.Show("You selected: " + MBR.ToString());
答案 4 :(得分:1)
我会采用一种方法来使用事件来显示这种消息显示。然后,您可以通过订阅事件轻松决定是否要记录。
我将如何做到这一点:
首先为您的消息方法定义几个代理:
public delegate void DisplayMessage(string message);
public delegate bool DisplayDialogBox(string message, string caption);
这些可以用作业务逻辑类中的事件:
public class BusinessLogic
{
public event DisplayMessage DisplayMessage;
public event DisplayDialogBox DisplayDialogBox;
protected void OnDisplayMessage(string message)
{
var dm = this.DisplayMessage;
if (dm != null)
{
dm(message);
}
}
protected bool OnDisplayDialogBox(string message, string caption)
{
var ddb = this.DisplayDialogBox;
if (ddb != null)
{
return ddb(message, caption);
}
return false;
}
public void SomeMethod()
{
this.OnDisplayMessage("Hello, World!");
var result = this.OnDisplayDialogBox("Yes or No?", "Choose");
this.OnDisplayMessage(result.ToString());
}
}
现在调用代码如下所示:
var bl = new BusinessLogic();
bl.DisplayMessage += MsgDisplay.DisplayMessage;
bl.DisplayDialogBox += MsgDisplay.DisplayDialogBox;
bl.SomeMethod();
这在我的测试中很有效。
现在,一个警告 - DisplayDialogBox
委托返回bool
所以当它被用作事件处理程序时,你可以让多个订阅者附加到事件,然后只返回最后一个返回值,但所有订阅者都将处理该事件。您可以弹出对话框,用户显示“否”,但下一个处理程序返回“是”,这就是返回的内容。
有一个相对容易的修复。将行return ddb(message, caption);
替换为:
return ddb
.GetInvocationList()
.Cast<DisplayDialogBox>()
.Select(d => d(message, caption))
.Aggregate((b1, b2) => b1 || b2);
只要您选择适当的聚合函数 - ||
,&&
- 或按bool
分组并选择计数最高的聚合函数 - 那么它就会很好用。
如果有帮助,请告诉我。