(转)关于生活中的设计模式(二)
2013-11-05 12:18
393 查看
原文地址:http://www.cnblogs.com/hankskfc/p/3408148.html
上篇文章中讨论了以“每个过程”为观察点来处理订单流程。我们定义了一个接口IAction
[code]{
[/code]
还定义了每个过程“拍下商品”、“付钱到支付宝”…
[code]{
[/code]
以及还有一个负责将每个“过程”进行串联的管理类ActionManager
[code]{
[/code]
最后展示了调用方式:
[code]actionMgr.DoSomething();
[/code]
由于实际项目中呢?我们对于IAction每个“动作”(即DoA、DoB、DoC),都会做一些其他的与业务不怎么相关(如日志)或者说在不影响原先的业务逻辑前提下,我要增加一些业务逻辑(比如业务要求在4点之后客户不能确认收货)。
一开始我们的想法都是比较简单:直接在“确认收货”该过程里面修改逻辑代码!!以及在“每个过程”都添加日志的模块。然后将代码编译成dll文件,做个发布包就OK了。
这样的做法有点违反设计模式的“开闭原则”:“说软件实体(类,模块,函数等)应该可以扩展,但是不可以修改”。
那么有没有比较优美的做法来改变“直接修改类”的问题呢?
装饰者模式:自己内部拥有一个业务接口(即IAction),而且自己也实现这个业务接口(IAction)。
代码如下:
[code]{
[/code]
然后我们修改下ActionManager
[code]{
[/code]
这样的做法虽然满足了上述的要求,但是有个弊端就是每个方法几乎都被定死了即“DoC前”—>“DoC中”—>“DoC后”。在“DoC前和后”都已经规定死了要做什么,要是有些“过程”我们比较特殊(即我不要记日志,或者记日志的方式不一样了)。
面对这个问题我能想到的有两种做法:一个用接口IMethodBefore,IMethodAfter;另一种做法就是定义两个事件:OnActionBefore、OnActionAfter
事件的做法大家应该都会做的,也是比较用到的毕竟.Net就是以事件为驱动的。这里我就讲下接口的做法
接口定义如下:
[code]{
[/code]
然后呢我定义一个默认的做法类DefaultMethodAction
[code]{
[/code]
DefaultMethodAction用于如果没有其他的业务要求我们就做默认的的动作。
自定义的IMethodBefore,IMethodAfter该如何实现呢?这种实现有很多种方式,这里提供一种我的方式—反射、特性。
特性定义如下:
[code]{
[/code]
修改下ProcedureWrapper类代码如下:
[code]{
[/code]
然后就是我们的每个过程“用法”
[code]{
[/code]
我们最终的调用方式还是和原来一样,代码如下:
[code]actionMgr.DoSomething();
[/code]
上篇文章中讨论了以“每个过程”为观察点来处理订单流程。我们定义了一个接口IAction
publicinterfaceIAction
[code]{
voidDoA();
voidDoB();
voidDoC();
....
}
[/code]
还定义了每个过程“拍下商品”、“付钱到支付宝”…
publicclass拍下商品:IAction
[code]{
voidDoA();
voidDoB();
voidDoC();
}
publicclass付款到支付宝:IAction
{
voidDoA();
voidDoB();
voidDoC();
}
[/code]
以及还有一个负责将每个“过程”进行串联的管理类ActionManager
publicclassActionManager
[code]{
privateIAction_action=null;
publicActionManager(IActionaction)
{
_action=action;
}
publicvoidDoSomething()
{
_action.DoA();
_action.DoB();
_action.DoC();
...
}
}
[/code]
最后展示了调用方式:
varactionMgr=newActionManager(拍下商品);
[code]actionMgr.DoSomething();
[/code]
由于实际项目中呢?我们对于IAction每个“动作”(即DoA、DoB、DoC),都会做一些其他的与业务不怎么相关(如日志)或者说在不影响原先的业务逻辑前提下,我要增加一些业务逻辑(比如业务要求在4点之后客户不能确认收货)。
一开始我们的想法都是比较简单:直接在“确认收货”该过程里面修改逻辑代码!!以及在“每个过程”都添加日志的模块。然后将代码编译成dll文件,做个发布包就OK了。
这样的做法有点违反设计模式的“开闭原则”:“说软件实体(类,模块,函数等)应该可以扩展,但是不可以修改”。
那么有没有比较优美的做法来改变“直接修改类”的问题呢?
优化版做法
在23种设计模式中就有一个符合解决上述问题的解决方案——“装饰者模式”。我的理解就是一个“包装类”,生活中有很多这种例子比如中秋节买的月饼,里面的东西都是差不多的可是在经过盒子的“包装”后让人顿时感觉就“高端大气上档次”了。装饰者模式:自己内部拥有一个业务接口(即IAction),而且自己也实现这个业务接口(IAction)。
代码如下:
publicvoidProcedureWrapper:IAction
[code]{
privateIAction_innerAction=null;
publicProcedureWrapper(IActionaction)
{
_innerAction=action;
}
publicvoidDoA()
{
//做一些其他的事情;比如4点之后不执行改动作,直接return;
try
{
_innerAction.DoA();
}catch
{
//记录些日志
}
//改过程完成之后;做一些事情。
}
publicvoidDoB()
{
//做一些其他的事情;比如4点之后不执行改动作,直接return;
try
{
_innerAction.DoB();
}catch
{
//记录些日志
}
//改过程完成之后;做一些事情。
}
publicvoidDoC()
{
//做一些其他的事情;比如4点之后不执行改动作,直接return;
try
{
_innerAction.DoC();
}catch
{
//记录些日志
}
//改过程完成之后;做一些事情。
}
}
[/code]
然后我们修改下ActionManager
publicclassActionManager
[code]{
privateIAction_action=null;
publicActionManager(IActionaction)
{
if(action!=null)
{
_action=ProcedureWrapper(action);
}
}
publicvoidDoSomething()
{
if(action!=null)
{
_action.DoA();
_action.DoB();
_action.DoC();
}
}
}
[/code]
这样的做法虽然满足了上述的要求,但是有个弊端就是每个方法几乎都被定死了即“DoC前”—>“DoC中”—>“DoC后”。在“DoC前和后”都已经规定死了要做什么,要是有些“过程”我们比较特殊(即我不要记日志,或者记日志的方式不一样了)。
面对这个问题我能想到的有两种做法:一个用接口IMethodBefore,IMethodAfter;另一种做法就是定义两个事件:OnActionBefore、OnActionAfter
事件的做法大家应该都会做的,也是比较用到的毕竟.Net就是以事件为驱动的。这里我就讲下接口的做法
接口定义如下:
publicinterfaceIMethodBefore
[code]{
voidDoBefore();
}
publicinterfaceIMethodAfter
{
voidDoAfter();
}
[/code]
然后呢我定义一个默认的做法类DefaultMethodAction
publicclassDefaultMethodAction:IMethodBefore,IMethodAfter
[code]{
publicDoBefore()
{
//做一些通用的事情;如上述的“4点之后不执行该动作”
}
publicDoAfter()
{
//做一些通用的事情;如上述的“4点之后不执行该动作”
}
}
[/code]
DefaultMethodAction用于如果没有其他的业务要求我们就做默认的的动作。
自定义的IMethodBefore,IMethodAfter该如何实现呢?这种实现有很多种方式,这里提供一种我的方式—反射、特性。
特性定义如下:
publicclassBeforeAttribute:Attribute
[code]{
publicIMethodBeforeMethodBefore{get;privateset;}
publicBeforeAttribute(IMethodBeforebefore)
{
MethodBefore=before;
}
}
publicclassAfterAttribute:Attribute
{
publicIMethodAfterMethodAfter{get;privateset;}
publicBeforeAttribute(IMethodAfterbefore)
{
MethodAfter=before;
}
}
[/code]
修改下ProcedureWrapper类代码如下:
publicclassProcedureWrapper:IAction
[code]{
privateIMethodBefore_defaultBefore=null;
privateIMethodAfter_defaultAfter=null;
privateIAction_action=null;
///<summary>
///key:方法名称
///</summary>
privateDictionary<string,IMethodBefore>methodBefore=newDictionary<string,IMethodBefore>();
///<summary>
///key:方法名称
///</summary>
privateDictionary<string,IMethodAfter>methodAfter=newDictionary<string,IMethodAfter>();
publicProcedureWrapper(IActionaction)
{
_defaultBefore=newDefaultMethodAction();
_defaultAfter=newDefaultMethodAction();
_action=action;
varmethods=_action.GetType().GetMethods();
foreach(varmethodInfoinmethods)
{
varmethodName=methodInfo.Name.ToLower();
varattrBefore=methodInfo.GetCustomAttributes(typeof(BeforeAttribute),true);
if(attrBefore.Any())
{
varbefore=attrBefore[0]asBeforeAttribute;
if(before!=null)methodBefore.Add(methodName,before.MethodBefore);
}
varattrAfter=methodInfo.GetCustomAttributes(typeof(AfterAttribute),true);
if(attrAfter.Any())
{
varafter=attrBefore[0]asAfterAttribute;
if(after!=null)methodAfter.Add(methodName,after.MethodAfter);
}
}
}
publicvoidDoA()
{
IMethodBeforebefore=_defaultBefore;
IMethodAfterafter=_defaultAfter;
conststringkey="doa";
if(methodBefore.ContainsKey(key))
{
before=methodBefore[key];
}
before.DoBefore();
try
{
_action.DoA();
}
catch(Exception)
{
throw;
}
if(methodAfter.ContainsKey(key))
{
after=methodAfter[key];
}
after.DoAfter();
}
publicvoidDoB()
{
IMethodBeforebefore=_defaultBefore;
IMethodAfterafter=_defaultAfter;
conststringkey="dob";
if(methodBefore.ContainsKey(key))
{
before=methodBefore[key];
}
before.DoBefore();
try
{
_action.DoB();
}
catch(Exception)
{
throw;
}
if(methodAfter.ContainsKey(key))
{
after=methodAfter[key];
}
after.DoAfter();
}
publicvoidDoC()
{
IMethodBeforebefore=_defaultBefore;
IMethodAfterafter=_defaultAfter;
conststringkey="doc";
if(methodBefore.ContainsKey(key))
{
before=methodBefore[key];
}
before.DoBefore();
try
{
_action.DoC();
}
catch(Exception)
{
throw;
}
if(methodAfter.ContainsKey(key))
{
after=methodAfter[key];
}
after.DoAfter();
}
}
[/code]
然后就是我们的每个过程“用法”
publicclass拍下商品:IAction
[code]{
//在这里你可以打上BeforeAttribute或者AfterAttribute,也可以不打上面的两个标签,让其走默认的做法
publicvoidDoA()
{
}
publicvoidDoB()
{
}
publicvoidDoC()
{
}
}
[/code]
我们最终的调用方式还是和原来一样,代码如下:
varactionMgr=newActionManager(拍下商品);
[code]actionMgr.DoSomething();
[/code]
相关文章推荐
- 关于生活中的设计模式(二)
- 关于MVP设计模式 和 BaseRecyclerViewAdapterHelperV2.4.4 Android
- 设计模式-关于模式的一些很基本的知识点
- 关于23种设计模式的有趣见解
- 关于23种设计模式的有趣见解
- 关于23种设计模式的有趣见解
- 关于IOS生命周期和设计模式
- 关于23种设计模式的有趣见解(转载
- [Head First设计模式]生活中学设计模式——外观模式
- 关于单态设计模式--static的妙用
- 转chgaowei关于设计模式的观点,跟我意见一致
- 关于Java 23种设计模式的有趣见解(转,地址不详)
- 关于IPHONE的设计模式
- 关于23种设计模式的有趣见解
- 关于设计模式
- java关于23种设计模式的有趣见解
- 设计模式关于软件工程
- 关于设计模式
- 模式人生-从生活中的点点滴滴认识设计模式1-装饰器模式(Decorator Pattern)
- 关于23种设计模式的有趣见解(转)