Nerdy tidbits from my life as a software engineer

Monday, February 2, 2009

Nested Classes

There’s really nothing I hate more than non-private inner classes.  In most cases, when you write something like this:

public class Whatever
{
  public void SomethingInteresting()
  {
   SomeNamespace.SomeClass c = new SomeNamespace.SomeClass();
   ...
  }
}

You can make your life easier by using the namespace:

using SomeNamespace;

public class Whatever
{
  public void SomethingInteresting()
  {
   SomeClass c = new SomeClass();
   ...
  }
}

This is particularly nice when you get some long-winded namespaces and class names.  There’s nothing more annoying to me to see your code cluttered with all sorts of useless garbage, like:

public void SomethingInteresting()
{
  Some.Very.Long.Namespace.SomeClassNameThatIsLong c = new Some.Very.Long.Namespace.SomeClassNameThatIsLong()
}

Ask yourself, is it really necessary to spell out the entire qualified name all over the place?  All this is really doing is killing the readability of your code for no tangible benefit.  Remember that if you are really concerned with clarifying the location of a particular class you can use the namespace but still write the fully qualified name.  At least in those cases you have the option, and you are not forcing your users to style their code one way or the other.

Now let’s figure that you decide you like using public inner classes, for some reason that makes no sense to me.  So you have something like this:

namespace SomeNamespace
{
  public class Outer
  {
    ...
    public class Inner
    {
    }
  }
}
...
public void ThisIsAnnoying()
{
  SomeNamespace.Outer.Inner silly = new SomeNamespace.Outer.Inner();
  ...
}

In this case, it is unclear that Outer is a class and not a namespace.  But what’s really annoying is the fact that even if you import  SomeNamespace into your class, you can only make your life so much easier because you cannot escape a class like you can a namespace:

namespace SomeNamespace
{
  public class Outer
  {
    ...
    public class Inner
    {
    }
  }
}
...

using SomeNamespace;

public void ThisIsAnnoying()
{
  Outer.Inner silly = new Outer.Inner();
  ...
}

You have now, as a designer, forced your users into at least partially-qualifying the path to the Inner class.  What is the benefit of this?  So long as Inner is being consumed outside of Outer, there is literally no benefit to having it nested inside another class.

There is one good time to use inner classes.  If you want to hide the implementation of a class or interface and only expose it by it’s abstraction, a nested inner class works well as part of a factory pattern:

namespace SomeNamespace
{
  public class Factory
  {
   
   public ISomeInterface Create()
   { 
      return new Inner();
   }
    ...
    private class Inner : ISomeInterface
    {
      ...
    }
  }
}
...

using SomeNamespace;

public void ThisIsAnnoying()
{
  Factory f = new Factory();
  ISomeInterface i = f.Create();
  ...
}

This is can be a very good design in the right circumstances.  The reason why is because you are forcing a decoupling between ISomeInterface’s design and it’s behavior.  You are, in fact, forcing clients not to care how the instance returned by Create works, because by making Inner private, it can only be constructed through the factory class.  It is only exposed through the abstraction, not it’s implementation.  This ensures that the behavior of Inner is contained within the Factory class and that nobody else needs to know – or can know – how it works.

But in all other cases, all you’re really doing is making developers’ lives more complicated by forcing them to spell.everything.out for no reason.

0 comments: