Pages

Saturday, May 11, 2019

Problems of the 'new' keyword

How do we create an object in most languages? It's by using the 'new' keyword and there's a big problem lurking in there! Some languages of-course skip it, like Python, where you can create an instance of class just by doing 'ClassName()' instead of 'new ClassName()' but the underlying problem remains the same.

The new keyword causes our codes to get coupled.

Let's take this simple example:

interface IShape
{
  public string Name { get; }
}
class Square : IShape
{
  public string Name { get; private set; }
  public Square()
  {
    Name = "Square";
  }
}
class Circle : IShape
{
  public string Name { get; private set; }
  public Circle()
  {
    Name = "Circle";
  }
}
class ShapeHolder
{
  public IShape Shape { get; private set; }
  ShapeHolder()
  {
    shape = new Square();
  }
}

If we see the above example, even though we have used an interface 'IShape', our ShapeHolder is now tightly coupled to the Square instance. It can never ever hold an instance of a circle. This may seem fine but this causes two major problems:
  1. Unit Tests: There's no way to test ShapeHolder independently of Square class. Any test written for ShapeHolder would end up working with a concrete instance of Square class. If Square class was modified later to start using network access or a db call, unit tests of ShapeHolder may start failing or take up huge amounts of time, as the testing environment won't have the necessary setups.
  2. Extensibility: The above code doesn't show run time polymorphism. In future if a new shape comes in, which must work with the ShapeHolder class, we will have to modify the ShapeHolder class too. This may in-turn cause some other class to be modified. This is a violation of open closed principle.
The main way to solve this is to use Dependency Inversion. Instead of ShapeHolder being responsible for creating the Square class, it should be passed in to the class, either via the parameter of the constructor or using something like the Factory design pattern. Now at runtime we can change which IShape type is being held by the ShapeHolder. For unit tests, this can be a simple MockShape class.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.