閱讀458 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Enterprise Library深入解析與靈活應用(3):倘若將Unity、PIAB、Exception Handling引入MVP模式.. .. ..

最近在做一個Smart Client Software Factory的項目。熟悉SCSF或者CAB的都應該很清楚MVP這種設計模式。MVP是MVC的一種變體,View和Mode分別關注於UI的呈現和業務模型,View和Mode完全分離,View通過Presenter實現對業務模型的訪問,Presenter“間接”地調用View實現對UI的操作。對於MVP中的異常處理,我們是直接通過Enterprise Library的Exception Handling Application Block來實現的。具體的做法是:在View中的每個控件的事件中添加try/catch block, 並在catch中通過ExceptionPolicy實現對異常的處理。這樣導致的問題是,相同的代碼重複散布於整個應用的各個角落,所以我又這樣的想法:通過Policy Injection以AOP的方式實現對異常的處理,當有了這個想法後,我又多想了一步,何不再將Unity也一並整合進來。(Source Code 下載)

image

image

1、ICalculator:Calculator的接口,定義了一個用於進行除法運算的操作

namespace Artech.UnityInMVP
{
    public interface ICalculator
    {
        int Divide(int op1, int op2);
    }
}

2、Calculator:實現了ICalculator接口

namespace Artech.UnityInMVP
{
    public class Calculator:ICalculator
    {
        public  int Divide(int op1, int op2)
        {
            return op1 / op2;
        }
    }
}

3、CalculatePresenter:被View調用進行數學運算,並將運算結果顯示到View中

namespace Artech.UnityInMVP
{
     public class CalculatePresenter
    {
        public CalculatePresenter()
        {
           this.Calculator = new Calculator();
        }

        public ICalculateView View
        { get; set; }

        public ICalculator Calculator
        { get; set; }

        public void Calculate(int op1, int op2)
        {
            int result = this.Calculator.Divide(op1, op2);
            this.View.DisplayResult(result);
        }
    }
}

4、ICalculateView :定義了一個用於顯示運算結果的操作,該操作被CalculatePresenter調用

namespace Artech.UnityInMVP
{
   public interface ICalculateView
    {
        void DisplayResult(int result);
    }
}

5、CalculateView:在本例中是一個Form,並實現了ICalculateView

image

namespace Artech.UnityInMVP
{
    public partial class CalculateView : ICalculateView
    {      

        public CalculatePresenter Presenter
        { get; set; }

        public void DisplayResult(int result)
        {
            this.textBoxResult.Text = result.ToString();
        }

        private void buttonCalculate_Click(object sender, EventArgs e)
        {
            int op1;
            int op2;
            if(!int.TryParse(this.textBoxOp1.Text.Trim(), out op1))
            {
                return;
            }

             if(!int.TryParse(this.textBoxOp2.Text.Trim(), out op2))
            {
                return;
            }

try
             {
                 this.Presenter.Calculate(op1, op2);
         
   }
          
  catch (Exception ex)
             {
                 if (ExceptionPolicy.HandleException(ex, "UI Exception Policy"))
                 {
                     throw;
                 }
             }
        }

        private void CalculateView_Load(object sender, EventArgs e)
        {
            this.Presenter = new CalculatePresenter ();
            this.Presenter.View = this;
        }
    }
}

namespace Artech.UnityInMVP
{
   
    public class CalculatePresenter:
    {
        public CalculatePresenter()
        {
            this.Calculator = new Calculator();
        }

        public ICalculateView View
        { get; set; }

[Dependency]
        public ICalculator Calculator
        { get; set; }

        public void Calculate(int op1, int op2)
        {
            int result = this.Calculator.Divide(op1, op2);
            this.View.DisplayResult(result);
        }
    }
}

  • 為了讓Policy Injection能夠起作用,我讓其繼承,並且以Custom Attribute的形式應用了ExceptionCallHandler,並製定exception handling policy(在真正的項目開發中,我推薦通過configuration的方式應用Policy injection)。
  • 通過實現了基於Unity的Property dependency.

然後我們接著對View進行改造,由於我們在CalculatePresenter使用了和我們需要通過Unity Container的方式來創建CalculatePresenter對象,為此我定義了View的基類:ViewBase.

namespace Artech.UnityInMVP
{
    public partial class ViewBase : Form
    {     

        protected IUnityContainer UnityContainer
        {
            get
            {
                if (this._unityContainer == null)
                {
                    this._unityContainer = new UnityContainer();
                    UnityConfigurationSection unityConfigSection = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
                    unityConfigSection.Containers.Default.Configure(this._unityContainer);
                }
                return this._unityContainer;
            }
        }
    }
}

namespace Artech.UnityInMVP
{
    public partial class CalculateView : ViewBase, ICalculateView
    {
        public CalculateView()
        {
            InitializeComponent();                   
        }

        public CalculatePresenter Presenter
        { get; set; }

        public void DisplayResult(int result)
        {
            this.textBoxResult.Text = result.ToString();
        }

        private void buttonCalculate_Click(object sender, EventArgs e)
        {
            int op1;
            int op2;
            if(!int.TryParse(this.textBoxOp1.Text.Trim(), out op1))
            {
                return;
            }

             if(!int.TryParse(this.textBoxOp2.Text.Trim(), out op2))
            {
                return;
            }

this.Presenter.Calculate(op1, op2);
        }

        private void CalculateView_Load(object sender, EventArgs e)
        {
            this.Presenter =
            this.Presenter.View = this;
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </configSections>
  <exceptionHandling>
    <exceptionPolicies>
      <add name="UI Exception Policy">
        <exceptionTypes>
          <add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="None" name="Exception">
            <exceptionHandlers>
              <add type="Artech.UnityInMVP.ExceptionHandlers.MessageBoxHandler,Artech.UnityInMVP"
                name="Custom Handler" />
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
    </exceptionPolicies>
  </exceptionHandling>
  <unity>
    <containers>
      <container>
        <types>
            <type type=" Artech.UnityInMVP.ICalculator,Artech.UnityInMVP" mapTo="Artech.UnityInMVP.Calculator,Artech.UnityInMVP"/>
        </types>
        <extensions>
          <add type="Artech.UnityInMVP.UnityExtensions.PolicyInjectionExtension,Artech.UnityInMVP" />
        </extensions>
      </container>
    </containers>
  </unity>
</configuration>

<exceptionHandling>
    <exceptionPolicies>
      <add name="UI Exception Policy">
        <exceptionTypes>
          <add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="None" name="Exception">
            <exceptionHandlers>
              <add type="Artech.UnityInMVP.ExceptionHandlers.MessageBoxHandler,Artech.UnityInMVP"
                name="Custom Handler" />
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
    </exceptionPolicies>
  </exceptionHandling>

 


<unity>
    <containers>
      <container>
        <types>
            <type type=" Artech.UnityInMVP.ICalculator,Artech.UnityInMVP" mapTo="Artech.UnityInMVP.Calculator,Artech.UnityInMVP"/>
        </types>
        <extensions>
          <add type="Artech.UnityInMVP.UnityExtensions.PolicyInjectionExtension,Artech.UnityInMVP" />
        </extensions>
      </container>
    </containers>
  </unity>
這就使所有的實現。如何運算出現異常,比如將第二個操作數設為零,我們定義的MessageBoxHandler就會被執行,並通過MessageBox將Message顯示出來,就像這樣:

image

 

P.S. 雖然講Policy Injection應用到Presenter可以通過AOP的方式來進行異常的處理,但是這要求View上的所有具有潛在異常拋出的邏輯都需要通過Presenter來實現,因為ExceptionHandler是應用到Presenter上麵的。


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-30 17:04:20

  上一篇:go  WCF後續之旅(11): 關於並發、回調的線程關聯性(Thread Affinity)
  下一篇:go  在TensorFlow中對比兩大生成模型:VAE與GAN(附測試代碼)