Saturday, April 19, 2008

Interface Segregation Principle

The principle states: Clients should not be forced to depend upon interfaces that they do not use. Below is an example of some code breaking this principle:

Interface: ICarConfigurator
1
2
3
4
5
6
7
8
9
namespace ISP
{
    public interface ICarConfigurator
    {
        string ExteriorColor { get; set; }
        string InteriorColor { get; set; }
        string EngineType { get; set; }
    }
}
Class: CarConfigurator : ICarConfigurator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
namespace ISP
{
    public class CarConfigurator : ICarConfigurator
    {
        private string _ExteriorColor;
        private string _InteriorColor;
        private string _EngineType;

        public string ExteriorColor
        {
            get { return _ExteriorColor; }
            set { _ExteriorColor = value; }
        }
        public string InteriorColor
        {
            get { return _InteriorColor; }
            set { _InteriorColor = value; }
        }
        public string EngineType
        {
            get { return _EngineType; }
            set { _EngineType = value; }
        }
    }
}
Class: DrawExterior
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace ISP
{
    public class DrawExterior
    {
        private readonly ICarConfigurator _Car;

        public DrawExterior(ICarConfigurator car)
        {
            _Car = car;
        }

        public void Draw()
        {
            Console.WriteLine("The car will have this exterior color: "+ _Car.ExteriorColor);
        }
    }
}
Class: DrawInterieur
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace ISP
{
    public class DrawInterieur
    {
        private readonly ICarConfigurator _Car;

        public DrawInterieur(ICarConfigurator car)
        {
            _Car = car;
        }

        public void Draw()
        {
            Console.WriteLine("The car will have this interior color: "+ _Car.InteriorColor);
        }
    }
}
Class: DrawEngine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace ISP
{
    public class DrawEngine
    {
        private readonly ICarConfigurator _Car;

        public DrawEngine(ICarConfigurator car)
        {
            _Car = car;
        }

        public void Draw()
        {
            Console.WriteLine("The car will have this engine: "+ _Car.EngineType);
        }
    }
}
In the above example you see one class CarConfigurator interface implementing interface ICarConfigurator that is being used by three different classes; DrawExterior, DrawInterieur and DrawEngine. All these different classes are using different functionality of the ICarConfigurator interface this means that all of these classes are connected to each other and if there is a change for one class in the interface than this will affect all of them.

Below you will see the same example but now accordingly to the Interface Segregation Principle:
Interface: ICarExterior
1
2
3
4
5
6
7
namespace ISP
{
    public interface ICarExterior
    {
        string ExteriorColor { get; set; }
    }
}
Interface: ICarInterior
1
2
3
4
5
6
7
namespace ISP
{
    public interface ICarInterior
    {
        string InteriorColor { get; set; }
    }
}
Interface: ICarEngine
1
2
3
4
5
6
7
namespace ISP
{
    public interface ICarEngine
    {
        string EngineType { get; set; }
    }
}
Class: CarConfigurator : ICarExterior, ICarInterior, ICarEngine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
namespace ISP
{
    public class CarConfigurator : ICarExterior, ICarInterior, ICarEngine
    {
        private string _ExteriorColor;
        private string _InteriorColor;
        private string _EngineType;

        public string ExteriorColor
        {
            get { return _ExteriorColor; }
            set { _ExteriorColor = value; }
        }
        public string InteriorColor
        {
            get { return _InteriorColor; }
            set { _InteriorColor = value; }
        }
        public string EngineType
        {
            get { return _EngineType; }
            set { _EngineType = value; }
        }
    }
}
Class: DrawExterior
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace ISP
{
    public class DrawExterior
    {
        private readonly ICarExterior _Car;

        public DrawExterior(ICarExterior car)
        {
            _Car = car;
        }

        public void Draw()
        {
            Console.WriteLine("The car will have this exterior color: "+ _Car.ExteriorColor);
        }
    }
}
Class: DrawInterieur
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace ISP
{
    public class DrawInterieur
    {
        private readonly ICarInterior _Car;

        public DrawInterieur(ICarInterior car)
        {
            _Car = car;
        }

        public void Draw()
        {
            Console.WriteLine("The car will have this interior color: "+ _Car.InteriorColor);
        }
    }
}
Class: DrawEngine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace ISP
{
    public class DrawEngine
    {
        private readonly ICarEngine _Car;

        public DrawEngine(ICarEngine car)
        {
            _Car = car;
        }

        public void Draw()
        {
            Console.WriteLine("The car will have this engine: "+ _Car.EngineType);
        }
    }
}
I hope you found these examples helpful. Also take a look at the following links:

http://www.objectmentor.com/resources/articles/isp.pdf
http://www.lostechies.com/blogs/rhouston/archive/2008/03/14/ptom-the-interface-segregation-principle.aspx
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

1 comment:

Anonymous said...

Good One!