使用装饰器模式分离职责


 我们因为安全、调试或是其他的什么原因,经常需要在我们的程序中插入记录日志的代码,在MS 的 Enterprise Library中, 也提供了日志程序块,由此可见,日志对于任何一个系统都是很重要的。

 通常,我们记录的做法是这样的

None.gif      class  Business
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        
public virtual void DoSomeWork ()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
//一些处理业务的代码
InBlock.gif
InBlock.gif                
// 写操作成功日志
ExpandedSubBlockEnd.gif
            }

InBlock.gif            
catch
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
// 写操作失败日志
InBlock.gif
                throw;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif}

None.gif

当然,假设我们使用工厂来创建业务对象。  

None.gif class  BusinessFactory
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        
public static Business CreateBusiness(bool needLog)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{            
InBlock.gif            
return new Business(needLog);            
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif}

调用代码           

None.gif Business biz  =  BusinessFactory.CreateBusiness( false );
None.gif            
None.gifbiz. DoSomeWork ();

 

 这些代码工作的很好,但是我们不难发现,我们写日志的代码夹杂在业务逻辑代码之中,而且,我们为了记录业务执行失败的情况,甚至在其中插入了本来可能不必要的异常处理—try/catch块。这使我们的业务逻辑代码变得臃肿而且难以维护。

 记住 Fowler 告诉我们的:重构以使用模式。经过一段时间的冥思苦想,我发现 Decorator 模式正是用于解决此问题。重构的目的是将日志记录代码从业务逻辑代码中分离,重构步骤如下:


1、 新建一个 装饰类 ,从 Business 继承,并覆写其中的DoSomeWork 方法。
2、 将 异常处理和日志记录移至 派生类 中,使派生类中覆写的方法调用基类中的方法。
3、 更改工厂,使其返回派生类的实例。

重构以后的代码

业务类: 

None.gif class  Business
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        
public virtual void DoSomeWork()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif           
//一些处理业务的代码
ExpandedSubBlockEnd.gif
        }

ExpandedBlockEnd.gif}

None.gif
None.gif

业务的装饰类

   

None.gif class  LoggedBusiness : Business
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        
private Business biz;
InBlock.gif
InBlock.gif        
public LoggedBusiness(Business biz)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this.biz = biz;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public override void DoSomeWork()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                biz.DoSomeWork();
InBlock.gif                
// 写成功日志
ExpandedSubBlockEnd.gif
            }

InBlock.gif            
catch
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                
// 写失败日志
InBlock.gif
                throw;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }

None.gif

工厂

None.gif public   static  Business CreateBusiness( bool  needLog)
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif            Business biz 
= new Business();
InBlock.gif            
if( needLog )
InBlock.gif              
return new LoggedBusiness(biz);
InBlock.gif            
else
InBlock.gif              
return biz ;
ExpandedBlockEnd.gif    }

工厂的使用者,根本没有意识到,他所使用的对象已经悄悄的发生了改变。这也正是 装饰器 模式的优点 --- 对象的使用者根本不知道他所使用的对象已经被装饰了,但装饰器已经开始工作了。另外,我们可以在运行的时候决定是否使用 装饰类,只要稍稍修改工厂--在工厂中根据上下文判断是返回装饰类还是原始类的实例--就可以了。我们可以对对象使用多重装饰,以使其具有多重职责,这一点也很有用。


个人认为,装饰器的作用在于通过扩展的方式把附加的职责添加到原始对象上,本文介绍的只是它的一个小小的应用。
也有人认为,凡是需要用到装饰器模式的地方,都是需要三段话都是需要使用AOP的地方。AOP带来了代码的优雅,然而使用AOP却是有代价的,效率的或者是其他的代价。

转载于:https://www.cnblogs.com/QuitGame/archive/2005/12/13/296442.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值