Tuesday, July 26, 2011

The Interface Segregation Principle

In my previous post I talked about the Liskov Substitution principle, and how it targets public polymorphism by specifying consistent behavior for a method defined in a class and its sub-classes. We saw that derived methods should expect no more and provide no less, and that the IS A relationship pertains to behavior.

In this post, I continue with the fourth of the S.O.L.I.D. Object Oriented Design Principles, the Interface Segregation principle (ISP). As we could notice, all the principles overlap in many aspects and this one is not the exception. In the Single Responsibility I mentioned that it is very often that a programmer comes across classes whose public interfaces do "too much." This common problem is a major concern of the ISP as well; we can say that this principle targets Interface Pollution.

We detect the Interface Pollution smell when we see client classes that use just a little of the functionality exposed by other ones. This is a good time to do some refactoring and improve our design. Refactoring is a practice that every OOP programmer should do.

When object oriented applications are maintained, the interfaces to existing classes and components often change. When changes have a big impact like recompilation and redeployment, this impact can be mitigated by adding new interfaces to present objects, rather than modifying the current interface. This means, we can extend our published interface by defining a new one that contains these modifications without changing the published one; therefore, no client objects are affected as they would never notice this update.


The Interface Segregation principle defines the following:

- Clients should not be forced to depend upon Interfaces that they do not use.
- Many client specific Interfaces are better than one general purpose Interface (god class).


What does Client Specific Mean?
Clients should be categorized by their type, and interfaces for each type of client should be created. If two or more different client types need the same method, the method should be added to both of their interfaces. Also, to avoid method repetition, we can abstract the common behavior from these interfaces and define a base interface from which they can inherit (GoF Template Method pattern).

The following UML class diagrams picture the ISP:

The classes A, B and C are clients of the Service class who defines methods to be used by them. Each one of the client classes uses small and different portions of these methods.


Now, we create client specific interfaces, each interface is more granular and provides more cohesive definition for each client.

Code Sample:
Despite the following code is in C# it can be easily ported to Java or other OOP language.

Wrong implementation of this principle:

We define the class Animal, this class provides three methods with some animal capabilities; Swim, Fly and Run.

   1:  public class Animal
   2:  {
   3:      public virtual void Swim()
   4:      {
   5:          Console.WriteLine("I swim");
   6:      }
   7:   
   8:      public virtual void Fly()
   9:      {
  10:          Console.WriteLine("I fly");
  11:      }
  12:   
  13:      public virtual void Run()
  14:      {
  15:          Console.WriteLine("I run");
  16:      }
  17:  }

Now, we define three classes that inherit from Animal; Dog, Shark and Duck. Our abstraction is that these are animals, therefore it is safe to sub-class from the Animal class. As not all animals can support some of the capabilities, we implement an Exception when such methods are called to notify the programmer that such behaviors are not valid.

   1:  public class Dog : Animal
   2:  {
   3:      public override void Fly()
   4:      {
   5:          throw new InvalidOperationException("A dog cannot fly");
   6:      }
   7:  }
   8:   
   9:  public class Shark : Animal
  10:  {
  11:      public override void Fly()
  12:      {
  13:          throw new InvalidOperationException("A shark cannot fly");
  14:      }
  15:   
  16:      public override void Run()
  17:      {
  18:          throw new InvalidOperationException("A shark cannot run");
  19:      }
  20:  }
  21:   
  22:  public class Duck : Animal
  23:  {
  24:  }

For any client who uses a Dog object, it may be cumbersome to see that by calling the Fly method, an exception will be thrown regardless. The same client would perceive the Shark object even worse. For the client's point of view, the Dog and Shark classes public interface are "polluted."

A class ProgramClient is defined to make this problem clear to see.

   1:  class ProgramClient
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          Animal animal = null;
   6:   
   7:          Console.WriteLine("A Duck says: ");
   8:          animal = new Duck();
   9:          animal.Fly();
  10:          animal.Run();
  11:          animal.Swim();
  12:   
  13:          Console.WriteLine(Environment.NewLine + "A Dog says: ");
  14:          animal = new Dog();
  15:          animal.Fly();// Will throw an Exception
  16:          animal.Run();
  17:          animal.Swim();
  18:   
  19:          Console.WriteLine(Environment.NewLine + "A Shark says: ");
  20:          animal = new Shark();
  21:          animal.Fly();// Will throw an Exception
  22:          animal.Run();// Will throw an Exception
  23:          animal.Swim();
  24:          Console.ReadLine();
  25:      }
  26:  }

We will need to remove the method calls that throw Exception as per their implementation. Alongside our programming experience, we may have ended up with sub-classes where we left many of their derived methods with either, an empty body or throwing flavors of "Not Implemented Exceptions." This is a sign that we need to segregate the class interfaces, specially if we are the owners or have access to the source code.

Good implementation of this principle:

We follow the name of this principle by segregating our previous interface Animal. Now, we define ISwim, IFly and IRun interfaces as follows:

   1:  public interface ISwim
   2:  {
   3:      void Swim();
   4:  }
   5:   
   6:  public interface IFly
   7:  {
   8:      void Fly();
   9:  }
  10:   
  11:  public interface IRun
  12:  {
  13:      void Run();
  14:  }

We define our new Dog class only with the behaviors that such animal can do.

   1:  public class Dog : IRun, ISwim
   2:  {
   3:      public void Run()
   4:      {
   5:          Console.WriteLine("I run very fast");
   6:      }
   7:   
   8:      public void Swim()
   9:      {
  10:          Console.WriteLine("I can barely swim");
  11:      }
  12:  }

We do the same with the Shark and Duck classes:

   1:  public class Shark : ISwim
   2:  {
   3:      public void Swim()
   4:      {
   5:          Console.WriteLine("I swim all day long");
   6:      }
   7:  }
   8:   
   9:  public class Duck : IRun, ISwim, IFly
  10:  {
  11:      public void Run()
  12:      {
  13:          Console.WriteLine("I can barely run");
  14:      }
  15:   
  16:      public void Swim()
  17:      {
  18:          Console.WriteLine("I swim with no problem");
  19:      }
  20:   
  21:      public void Fly()
  22:      {
  23:          Console.WriteLine("I fly short distances");
  24:      }
  25:  }

Now, our ProgramClient class uses these objects intuitively without any problem. We have improved our design by abstracting a better way to expose animals behaviors. A client of Dog objects will never be given the choice to call the Fly method.

   1:  class ProgramClient
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          Console.WriteLine("A Duck says: ");
   6:          Duck duck = new Duck();
   7:          duck.Fly();
   8:          duck.Run();
   9:          duck.Swim();
  10:   
  11:          Console.WriteLine(Environment.NewLine + "A Dog says: ");
  12:          Dog dog = new Dog();
  13:          dog.Run();
  14:          dog.Swim();
  15:   
  16:          Console.WriteLine(Environment.NewLine + "A Shark says: ");
  17:          Shark shark = new Shark();
  18:          shark.Swim();
  19:          Console.ReadLine();
  20:      }
  21:  }

It is clear that we can provide better interfaces for our classes. We might have a new requirement for a SuperDog class, this would be simple to implement with the following definition.

   1:  public class SuperDog : Dog, IFly
   2:  {
   3:      public void Run()
   4:      {
   5:          Console.WriteLine("I can run super fast");
   6:      }
   7:   
   8:      public void Swim()
   9:      {
  10:          Console.WriteLine("I swim with no problem");
  11:      }
  12:   
  13:      public void Fly()
  14:      {
  15:          Console.WriteLine("I fly long distances");
  16:      }
  17:  }

We may consider to implement directly the IRun, ISwim and the IFly interfaces for this new SuperDog class instead of inheriting from Dog, otherwise our design is in risk to break the Liskov Substitution principle. This is because clients using Dog classes only, are not expecting "super" behaviors.

Also, for backward compatibility with our previous Animal class, we can make it implement our three new interfaces.

Conslusions:
We have seen how the ISP helps us to provide more granular and cohesive interfaces that our clients can understand and use. A good way of doing this is by dividing an interface into single responsibilities for each one of the interfaces to define; this is a clear sign that all the S.O.L.I.D. principles overlap. When we see a polluted interface doing "too much," we can apply the Interface Segregation principle to solve this problem.

I will cover the Dependency Inversion principle on my next post, the last of the S.O.L.I.D. Object Oriented Design Principles series. See you soon!

[RobertMartin96] SRP: The Interface Segregation Principle, Robert Martin, 1996

Thursday, July 21, 2011

The Liskov Substitution Principle

In my previous post I talked about the Open-Closed principle and how it is located at the heart of many claims made for OOD such as inheritance abstraction and polymorphism. Having a design open for extension and closed for modification is a major goal that every application architect or OOP programmer should pursue.

I would like to continue with the third of the  S.O.L.I.D. Object Oriented Design Principles, the Liskov Subtitution principle. This principle was defined by Barbara Liskov, a well respected computer scientist and the first women in the US to recieve a PhD in Computer Science.

This principle is an extension of the Open-Closed, and it targets Public Polymorphism mainly. Thus, a proper abstraction needs to be made when a public contract (class or interface) is attempted to be published, a published interface is that one whose public methods are in hands of external users (client classes).

The Liskov Subsitution Principle defines these two important aspects:

- Subclasses should be substitutable for their base classes.
- Methods that use references to base classes (interfaces) must be able to use objects of derived classes (implementer classes) without knowing it.


Design by Contract:
Methods of classes declare pre-conditions and post-conditions. The pre-conditions must be true in order for the method to execute. Upon completion, the method guarantees that the post-condition will be true.

LSP makes clear that in OOD the IS A (inheritance) relationship pertains to behavior. Not intrinsic private behavior, but extrinsic public behavior that clients depend upon. The clients expect constant behavior for published interfaces! 

Expected behavior: Derived methods should expect no more and provide no less.

The following UML class diagram pictures LSP:

Published interfaces used by clients will expect always the same behavior from derived classes as they may not be aware of these new implementation details.

Code sample:
Despite the following code is in C# it can be easily ported to Java or other OOP language.

First, we define the class Circle with the public attribute Radius and the public method CalculateArea, this last implements the formula to obtain the area of a circle.

   1:  public class Circle
   2:  {
   3:      public double Radius { get; set; }
   4:   
   5:      public virtual double CalculateArea()
   6:      {
   7:          // Pi * r^2
   8:          return Math.PI * Math.Pow(this.Radius, 2);
   9:      }
  10:   
  11:      public override string ToString()
  12:      {
  13:          return string.Format("Circle Radius {0} and Area {1}",
  14:              this.Radius, Math.Round(this.CalculateArea(), 3));
  15:      }
  16:  }

Second, we define the CircleChecker class that contains the static method PrintMatchesInSameIndex, this method takes two arrays of Circle instances and checks by the Radius attribute if two circles at the same index position of the the arrays are equivalent. It makes totally sense to compare by the Radius attribute if two Circle instances have the same size.
   1:  public class CircleChecker
   2:  {
   3:   
   4:      public static void PrintMatchesInSameIndex(Circle[] series1,
   5:                                                 Circle[] series2)
   6:      {
   7:          int lastIndex = series1.Length < series2.Length ?
   8:              series2.Length : series1.Length;
   9:          for (int i = 0; i < lastIndex; i++)
  10:          {
  11:              if (series1[i].Radius == series2[i].Radius)
  12:              {
  13:                  Console.WriteLine(string.Format(
  14:                      "Index {0}: \n" + series1[i].ToString()
  15:                      + " = " + series2[i].ToString(), i));
  16:              }
  17:          }
  18:      }
  19:  }

Finally, the CircleConsole class initializes two arrays of the type Circle and sets the values of the Radius attribute for each Circle object in the arrays. This class calls the static method of PrintMatchesInSameIndex in the CircleChecker class. The matching values are in bold.

   1:  class CircleConsole
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          const int length= 5;
   6:          int[] radiusSeries1 = new int[length] { 1, 2, 3, 4, 5 };
   7:          int[] radiusSeries2 = new int[length] { 1, 9, 3, 7, 5 };
   8:   
   9:          Circle[] series1 = new Circle[length];
  10:          Circle[] series2 = new Circle[length];
  11:   
  12:          for (int i = 0; i < length; i++)
  13:          {
  14:              series1[i] = new Circle();
  15:              series2[i] = new Circle();
  16:              series1[i].Radius = radiusSeries1[i];
  17:              series2[i].Radius = radiusSeries2[i];
  18:          }
  19:   
  20:          CircleChecker.PrintMatchesInSameIndex(series1, series2);
  21:          Console.ReadLine();
  22:      }
  23:  }

When executing the application, it is clear that the Circle objects at the indexes 0, 2 and 4 are equivalent:


So far so good, everything works as expected. To demonstrate the LSP we create the class Sphere that inherits from Circle. Our original thought may be that a Sphere is a specialization of a Circle, just made in 3D, right? Based on this premise, we override the CalculateArea method to calculate the surface of such Sphere and we extend the class by adding the CalculateVolume method.

   1:  public class Sphere : Circle
   2:  {
   3:      public override double CalculateArea()
   4:      {
   5:          // 4 * Pi * r^2
   6:          return 4 * Math.PI * Math.Pow(this.Radius, 2);
   7:      }
   8:   
   9:      public virtual double CalculateVolume()
  10:      {
  11:          // (4/3) * Pi * r^3
  12:          return (4 / 3) * Math.PI * Math.Pow(this.Radius, 3);
  13:      }
  14:  }

In theory, everything looks perfect! We have applied the Open-Closed principle as our designed was open for extension and we did not change other classes. However, we can see how the LSP is broken with the following implementation of the class SphereConsole, we instantiate Sphere objects for the series2 array of the type Circle.

   1:  class SphereConsole
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          const int length = 5;
   6:          int[] radiusSeries1 = new int[length] { 1, 2, 3, 4, 5 };
   7:          int[] radiusSeries2 = new int[length] { 1, 9, 3, 7, 5 };
   8:   
   9:          Circle[] series1 = new Circle[length];
  10:          Circle[] series2 = new Circle[length];
  11:   
  12:          for (int i = 0; i < length; i++)
  13:          {
  14:              series1[i] = new Circle();
  15:              series2[i] = new Sphere();
  16:              series1[i].Radius = radiusSeries1[i];
  17:              series2[i].Radius = radiusSeries2[i];
  18:          }
  19:   
  20:          CircleChecker.PrintMatchesInSameIndex(series1, series2);
  21:          Console.ReadLine();
  22:      }
  23:  }

When executing the application, we get unexpected results as seen in the following picture:


We can see that we have Circle instances with the same Radius value but different Areas! The LSP is broken as the static method PrintMatchesInSameIndex only understands the behavior of Circle objects, thus such behavior is expected.

Our main problem was bad abstraction, a Sphere is NOT a Circle! The client class CircleChecker is expecting constant behavior from any object that IS A Circle.

Conclusions:
We have seen why the Liskov Substitution Principle targets Public Polymorphism as clients of published interfaces can be affected by wrong sub-classing of such interfaces. Class inheritance needs to be used carefully. For the same reason, OOP languages provide guidelines to prevent this, we can declare a class to be sealed in C# or final in Java. By sealing the class Circle, we could avoid the Sphere class problem.

I will cover the Interface Segregation Principle in my next post, see you then!

[RobertMartin96] The Liskov Substitution Principle, Robert Martin, 1996

Monday, July 18, 2011

The Open-Closed Principle

In my previous post I covered the Single Responsibility principle which helps to provide cohesive interfaces to objects. An interface with high cohesion usually delivers low coupling or dependency with other interfaces. Also, these attributes provide maintainability and readability of our design. I would like to continue the series of the S.O.L.I.D. Object Oriented Design Principles; the second of them and my most favorite: the Open-Closed principle.

Every programmer who has used an OOP language knows fundamental concepts that define this paradigm, but the question is, how well these concepts are used. The Open-Closed principle is at the heart of many claims made for Object Oriented Design.

This principle targets the foundations of abstraction and polymorphism. A module should be open for extension but closed for modification.

Open for Extension:
The behavior of the module can be extended. We can make the module behave in NEW and DIFFERENT ways as the requirements of the application change.

Closed for Modification:
The source code of such module is INVIOLATE. No one is allowed to make source code changes to it.

Abstaction is the Key. The following UML class diagrams picture this principle:

The Client class depends directly on the Server class. Extending Server implementations is difficult and further changes may introduce complexity in code maintainability.

The Client class now depends on an abstraction of the Service by the Service Base Class. We can extend further implementation from this abstraction.

Code Sample:
Despite the following code is in C# it can be easily ported to Java or other OOP language.

Wrong implementation of this principle: 

   1:  class Point
   2:  {
   3:      private int x;
   4:      private int y;
   5:   
   6:      public Point(int x, int y)
   7:      {
   8:          this.x = x;
   9:          this.y = y;
  10:      }
  11:   
  12:      public int X
  13:      {
  14:          get { return this.x; }
  15:          set { this.x = value; }
  16:      }
  17:   
  18:      public int Y
  19:      {
  20:          get { return this.y; }
  21:          set { this.y = value; }
  22:      }
  23:   
  24:      public override string ToString()
  25:      {
  26:          return string.Format("X = {0}, Y = {1}", this.X, this.Y);
  27:      }
  28:  }
The class Point contains the coordinates X and Y.

Now we define the Circle and Square classes that we will use to draw instances of these classes in a canvas panel.
   1:  class Circle
   2:  {
   3:      public Circle(double radius, Point center)
   4:      {
   5:          this.Radius = radius;
   6:          this.Center = center;
   7:      }
   8:      public double Radius { get; set; }
   9:      public Point Center { get; set; }
  10:  }
  11:   
  12:  class Square
  13:  {
  14:      public Square(double side, Point topLeft)
  15:      {
  16:          this.Side = side;
  17:          this.TopLeft = topLeft;
  18:      }
  19:      public double Side { get; set; }
  20:      public Point TopLeft { get; set; }
  21:  }

We define the Canvas class where we draw instances of the Circle and Square classes.
   1:  class Canvas
   2:  {
   3:      void DrawSquare(Square square)
   4:      {
   5:          Console.WriteLine(string.Format(
   6:              "Square with side {0} and top left {1}",
   7:              square.Side, square.TopLeft));
   8:      }
   9:   
  10:      void DrawCircle(Circle circle)
  11:      {
  12:          Console.WriteLine(string.Format(
  13:              "Circle with radius {0} and center {1}",
  14:              circle.Radius, circle.Center));
  15:      }
  16:   
  17:      public void DrawAllShapes(object[] shapes)
  18:      {
  19:          for (int i = 0; i < shapes.Length; i++)
  20:          {
  21:              if (shapes[i].GetType() == typeof(Circle))
  22:              {
  23:                  this.DrawCircle((Circle)shapes[i]);
  24:              }
  25:              else if (shapes[i].GetType() == typeof(Square))
  26:              {
  27:                  this.DrawSquare((Square)shapes[i]);
  28:              }
  29:          }
  30:      }
  31:  }

We can see that the Canvas class implements methods to display each one of the figures; DrawSquare and DrawCircle. The public method DrawAllShapes receives an array of objects that will contain Square and Circle instances. The method checks for the type of each object to call the corresponding drawing method.

A major problem would be if we define the Triangle class because the Canvas class will need to be modified as well. We would need to implement a new method to draw Triangle objects and the DrawAllShapes method would need to change accordingly to call such method. This would happen for any new figure we want to add to our application.

This design breaks the Open-Closed principle clearly. Each time we need to extend our application by adding a new class, we need to modify other pre-existing classes (high coupling).

Good implementation of this principle:

We keep the Point class definition as we saw in the wrong implementation, the principle was not affected by this class after all. As specified previously, abstraction is the key, thus abstracting the common behavior of the figures will help to implement this principle properly.

An abstract class Shape defines the method Draw to be implemented by any specialization of this class.
   1:  abstract class Shape
   2:  {
   3:      public abstract void Draw();
   4:  }

Now, the classes Circle and Square inherit from the Shape class and each one is responsible to implement the specifics of their Draw method, hence each class knows how to draw itself, each class is the information expert of how to display itself in the canvas.
   1:  class Circle : Shape
   2:  {
   3:      public Circle(double radius, Point center)
   4:      {
   5:          this.Radius = radius;
   6:          this.Center = center;
   7:      }
   8:      public double Radius { get; set; }
   9:      public Point Center { get; set; }
  10:   
  11:      public override void Draw()
  12:      {
  13:          Console.WriteLine(
  14:              string.Format("Circle with radius {0} and center {1}",
  15:              this.Radius, this.Center));
  16:      }
  17:  }
  18:   
  19:  class Square : Shape
  20:  {
  21:      public Square(double side, Point topLeft)
  22:      {
  23:          this.Side = side;
  24:          this.TopLeft = topLeft;
  25:      }
  26:      public double Side { get; set; }
  27:      public Point TopLeft { get; set; }
  28:   
  29:      public override void Draw()
  30:      {
  31:          Console.WriteLine(
  32:              string.Format("Square with side {0} and top left {1}",
  33:              this.Side, this.TopLeft));
  34:      }
  35:  }

We remove the DrawCircle and DrawSquare methods from the class Canvas and modify the DrawAllShapes method whose parameter now is an array of the Shape type. Internally DrawAllShapes calls the method Draw of each of the Shape instances polymorphically.


   1:  class Canvas
   2:  {
   3:   
   4:      public void DrawAllShapes(Shape[] shapes)
   5:      {
   6:          for (int i = 0; i < shapes.Length; i++)
   7:          {
   8:              shapes[i].Draw();
   9:          }
  10:      }
  11:  }

It is now obvious that by using polymorphism we don't need to modify the class Canvas every single time that we add a new class that extends from the Shape class. We can define a new Triangle class that inherits from Shape without the need to modify Canvas. We have achieved the Open-Closed principle as our design is Open for extension in regards of adding new shapes and Closed for modification in terms of the canvas.

Conclusions:
We have seen how the Open-Closed principle uses inheritance and polymorphism, two core foundations of the OOP paradigm, and how this principle helps considerably with code maintenance and readability. Also, we could see how by abstracting and separating responsibilities our design was improved and ready to be extended harmlessly.

My next post will talk about the Liskov Substitution principle, see you soon!

[RobertMartin96] The Open-Closed Principle, Robert Martin, 1996