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 下载)
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
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>
<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显示出来,就像这样:
P.S. 虽然讲Policy Injection应用到Presenter可以通过AOP的方式来进行异常的处理,但是这要求View上的所有具有潜在异常抛出的逻辑都需要通过Presenter来实现,因为ExceptionHandler是应用到Presenter上面的。
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及着作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
最后更新:2017-10-30 17:04:20