开发者

Trying to refactor to Null object pattern but the end result seems worse

I'm refactoring a big class that has a lot of checks for null all over the place into using the null object pattern. So far it's been an almost smooth change but I am having a couple of issues with the end result and I would like to know if there is a better or different approach or even to go back the way it was.

The biggest problem is that I have the following code:

IMyObject myObject = GetMyObject();
if(myObject != null && !myObject.BooleanProperty)
   DoSomething();

So as you can see I could probably remove the null check from this condition but I have a boolean property which if set to the default value will execute a piece of code. If I always return true I might introduce subtle bugs that would be painful to find and eliminate.

Another problem is that I've had to modify a check from null like this:

if(myObject.GetType() != typeof(MyNullObject))
   return false;

DoSomething();

This is just plain ugly since instead of just checking for null, now I have to check the type. This kind of situation happens three times in the class since I am not returning one of the object's properties or executing one of its methods I must do this check.

And lastly the object has a couple of DateTime properties which are not nullable and the architect does not want them to be nullable. Again by having the MinDate value as default some nasty bugs could crawl into the code.

So there you have it. Is this a case in which the null object开发者_JAVA百科 pattern is just worse than the spaghetti null checks scattered all over? Is there a better way to accomplish this?

Thanks for your answers.


Would it be better to refactor your code so that DoSomething() is the method on Null Object and simply implemented as no-op? Another alternative to Null Object is Maybe<T>. It makes null checks a bit more readable and calling code safer.


The Null Object pattern is about a tradeoff - you gain with the elimination of null checks, but pay with another class to maintain.

I'd suggest adding an IsNull boolean property to your interface/base class.

The normal implementations return false; your null object returns true.

This allows you to avoid tests against exact types, and is clearer about your intent. You can also use this as a test in the code that deals with dates, allowing you to retain your non-nullable date properties.


You might add a boolean IsNull (IsEmpty) property in the interface IMyObject, then you implement MyNullObject that returns true for that property. Obviously you have to trust that in the other cases this should return false, otherwise you will have the wrong behaviour.


You should take a look at Code Contracts. This is an elegant way to enforce pre and post conditions on methods to avoid the sorts of issues you are referring to. It does this by raising exceptions early when the contract is broken at runtime, or in some cases through static analysis (Microsoft framework).

I prefer CuttingEdge Condtions, it doesn't support static analysis but it has a nice fluent interface and more intuitive than the Microsoft equivalent.

It allows you to write code like this, and even extend the interface:

public class MyClass
{
   public void MyMethod(string param1, int param2)
   {
       Condition.Requires(param1).IsNotNullOrWhiteSpace();
       Condition.Requires(param2).IsGreaterThan(0);

       ...
   }
}

You would implement conditions on all data input into the system, i.e. all public methods and prevent developers writing code that violates this. When it happens due to a bug, the exception and stack trace tells you exactly where the problem is.

There are also ways to set up conditions that monitor properties to ensure certain conditions never arise through Invariants. This can act as an anti-corruption layer which again catches bugs, and stops developers writing code the breaks the system.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜