使用 EmptyClass 避免条件判断
在习惯了使用基于接口的编程之后,经常会遇到这样的问题,比如,B组件需要使用实现了IA接口的A组件,但是如果在没有A组件的情况下B组件也可以正常工作,像这样:
public interface IA
{
void DoWork1() ;
void DoWork2() ;
}
public class B :IB
{
private IA theA ;
public B(IA a)
{
this.theA = a ;
}
public void DoJob()
{
//
if(this.theA != null)
{
this.theA.DoWork1() ;
}
}
public void DoOtherJob()
{
//
if(this.theA != null)
{
this.theA.DoWork2() ;
}
}
}
{
void DoWork1() ;
void DoWork2() ;
}
public class B :IB
{
private IA theA ;
public B(IA a)
{
this.theA = a ;
}
public void DoJob()
{
//
if(this.theA != null)
{
this.theA.DoWork1() ;
}
}
public void DoOtherJob()
{
//
if(this.theA != null)
{
this.theA.DoWork2() ;
}
}
}
可以看到很多地方都要用到if(this.theA != null)进行条件判断,如果某个地方露掉了这样的判断,运行时可能就会抛出“引用为空”的异常。有没有办法来彻底避免类似的条件判断了?有,那就是EmptyClass的目的。EmptyClass实现了比如上述的IA接口,但是EmptyClass什么都不做,即EmptyClass完全由VS.NET的智能感知自动生成(声明EmptyClass时,在写完接口名后按TAB键)。
我们看看自动生成的IA对应的EmptyClass:
public class EmptyA :IA
{
#region IA 成员
public void DoWork1()
{
// TODO: 添加 EmptyA.DoWork1 实现
}
public void DoWork2()
{
// TODO: 添加 EmptyA.DoWork2 实现
}
#endregion
}
{
#region IA 成员
public void DoWork1()
{
// TODO: 添加 EmptyA.DoWork1 实现
}
public void DoWork2()
{
// TODO: 添加 EmptyA.DoWork2 实现
}
#endregion
}
现在就可以在B中来避免前面的条件判断了:
public class B :IB
{
private IA theA ;
public B(IA a)
{
this.theA = a ;
// 如果引用为空,则赋值什么都不做的EmptyClass
if(this.theA == null)
{
this.theA = new EmptyA() ;
}
}
public void DoJob()
{
//
this.theA.DoWork1() ; // 不在需要条件判断!!!!!!!!
}
public void DoOtherJob()
{
//
this.theA.DoWork1() ;
}
}
{
private IA theA ;
public B(IA a)
{
this.theA = a ;
// 如果引用为空,则赋值什么都不做的EmptyClass
if(this.theA == null)
{
this.theA = new EmptyA() ;
}
}
public void DoJob()
{
//
this.theA.DoWork1() ; // 不在需要条件判断!!!!!!!!
}
public void DoOtherJob()
{
//
this.theA.DoWork1() ;
}
}
这个简单的小技巧,你一定已经学会了:)
在当一个组件对另一个组件的引用可以为空的时候,EmptyClass的实例就可以作为这个引用的默认值,这样不仅没有牺牲性能(空方法调用与条件判断的开销差不多),而且使得我们的代码更漂亮、更容易阅读和维护。