2011-09-20 91 views
3

我有一個winforms應用程序,我沒有遵循任何類型的設計模式。我的問題是,我有這些基類包含我所有的業務邏輯。當發生異常或我需要向用戶顯示一個對話框時,我已將代碼直接寫入需要它的基類中。C#,從業務邏輯中分離消息顯示代碼

我知道我需要分離業務邏輯和顯示邏輯,所以我編寫了一個靜態類,其中包含我需要顯示消息的方法。

我的問題是,是否有一種更簡單的方法將業務邏輯從顯示中分離出來?

我的靜態方法是這樣的,

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); 

,是這種方法的好的做法呢?

回答

2

不,這種方法不是一個好的做法。你的類和MessageBox類沒有任何區別。
看到,隨着你的等級:

MsgDisplay.DisplayMessage(e.Message); 

,只是使用的MessageBox

MessageBox.Show(e.Message); 

這個包裝不提供任何額外的功能。
如果你想分離業務邏輯和用戶界面,那麼你必須分解你的方法,並只在UI層顯示消息。
而且,小點。相反的:

if (newresult == DialogResult.OK) 
    { 
     return true; 
    } 
    else 
    { 
     return false; 
    } 

類型只是:

return newresult==DialogResult.OK 

UPDATE: 如果你想顯示的異常信息,那麼你應該抓住異常,並顯示用戶界面層上的消息。因此,在您的業務類,而不是顯示消息:

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); 
    } 
} 
+0

這是真的。這就是爲什麼我提出這個問題。你能舉一個如何分解一個方法的例子嗎?例如,如果我有我的mainForm和一個類的方法,在將來返回一個日期可以說。而這種方法可能會引發異常。我將如何分解顯示消息的方法?我很抱歉,這可能是一件非常簡單的事情,這是我建立的第一個應用程序,您的幫助表示感謝。 – shani

+0

沒有代碼就很難說出來。你可能想嘗試http://codereview.stackexchange.com/ –

+0

我最終打破了你在基類中建議的方法。並向UI層拋出異常。現在邏輯流程由UI層控制。感謝名單! – shani

1

一般,業務層將返回錯誤字符串。字符串通過GUI顯示在消息框或狀態欄中。

順便說一句,你可以從一個消息框的結果(你不需要一個對話框):

MessageBoxResult MBR = MessageBox.Show("Click Me", "Title", MessageBoxButton.YesNoCancel); 

MessageBox.Show("You selected: " + MBR.ToString()); 
+0

我不知道!我一直使用對話結果,謝謝。關於向GUI返回一個錯誤字符串,如果我有另一個需要從該方法返回的參數呢?如果我的方法需要返回一個int值,該怎麼辦?這將如何工作? – shani

+0

您可以使用返回值返回一個參數。其他參數可以使用out關鍵字返回:http://www.dotnetperls.com/out –

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

它比你想象的在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()(沒有參數)的東西。這是一個很長的方法名稱,但它非常明確,將實現和消息留給視圖,並且從長遠來看可以使事情變得更加清晰。

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);: - ||&& - 或組由bool並選擇具有最高計數 - 當你選擇一個適當的聚合功能

  return ddb 
       .GetInvocationList() 
       .Cast<DisplayDialogBox>() 
       .Select(d => d(message, caption)) 
       .Aggregate((b1, b2) => b1 || b2); 

只要那麼它會工作的偉大。

讓我知道這是否有幫助。

+0

我想過使用事件來做到這一點,但決定拆分我的基類中的方法,以便我的UI可以控制邏輯流程,並在必要時提示用戶。 Thankx回答! – shani