# JAL Computing

|  | # Chapter 16 "Designing Interfaces" In this chapter we are going to further explore the subject of interfaces. We are going to investigate the challenges of designing an interface, using composite interfaces and providing skeletal abstract classes. In Chapter 13, we defined an interface IDrawable to enable a plug-in architecture. Trying to modify the IDrawable interface provides a good example of the challenges of an evolving interface design. Here again is the IDrawable interface from Chapter 13:
    public interface IDrawable
    {
    	void DrawYourself(Graphics g, Point p, int size);
    }
Now let's say that we want to add a new argument such as color to the DrawYourself method like this:
    public interface IDrawable
    {
    	void DrawYourself(Graphics g, Point p, int size, Color c);
    }
The problem is that this would break compatibility with existing users of the old IDrawable interface. One solution would be to declare a new interface IColorable and implement color as a separate instance property. A colored shape class could then implement the IColorable interface without having to change the IDrawable interface.
    	public interface IColorable
    	{
    		Color c;
    		{
    			get;
    			set;
    		}
    	}
    	public class ColoredOval : IDrawable, IColorable
    	{
    		...
    	}
To take this a step further, we could refactor the IDrawable interface into three interfaces, IDrawable, IPositional and ISizeable. This provides a more general interface design at the cost of added complexity and class mutabilty.
    	public interface IDrawable
    	{
    		void DrawYourself(Graphics g);
    	}
    	// ASSERT P.X>=0 and P.Y>=0;
    	public interface IPositional
    	{
    		Point Position
    		{
    			get;
    			set;
    		}
    	}
    	public interface ISizeable
    	{
    		int Size
    		{
    			get;
    			set;
    		}
    	}
An Oval plug in class, for instance, would implement the IDrawable, IPositional and ISizeable interfaces like this:
    	public class Oval : IDrawable, ISizeable, IPositional
    	{
    		int size=1;
    		Point position= new Point(0,0);
    		public int Size
    		{
    			get {return size;}
    			set
    			{
    				if (value>0) {size= value;}
    			}
    		}
    		public Point Position
    		{
    			get {return position;}
    			set
    			{
    				if ((value.X >=0) && (value.Y >=0))
    				{
    					position= value;
    				}
    			}
    		}
    		public void DrawYourself(Graphics g)
    		{
    			Console.WriteLine("Oval");
    			{
    				g.DrawString("Oval",
    					new Font("Times", Size),
    					new SolidBrush(Color.Black),
    					Position.X, Position.Y);
    			}
    		}
    	}
The next step is to define a composite interface such as IBasicShape that combines the IDrawable, IPositional and ISizeable interfaces:
    public interface IBasicShape: IDrawable, IPositional, ISizeable {}
or IColoredShape
    public interface IColoredShape: IDrawable, IPositional, ISizeable, IColorable {}
We can then create an AbstractBasicShape skeletal class that provides a default implementation of IBasicShape:
    	public abstract class AbstractBasicShape : IBasicShape
    	{
    		int size=1;
    		Point position= new Point(0,0);
    		public int Size
    		{
    			get {return size;}
    			set
    			{
    				if (value>0) {size= value;}
    			}
    		}
    		public Point Position
    		{
    			get {return position;}
    			set
    			{
    				if ((value.X >=0) && (value.Y >=0))
    				{
    					position= value;
    				}
    			}
    		}
    		virtual public void DrawYourself(Graphics g)
    		{
    			System.Console.WriteLine("BasicShape");
    		}
    	}
The concrete shape class can then inherit from AbstractBasicShape and override the default implementation of DrawYourself:
    	public class Triangle : AbstractBasicShape
    	{
    		public override void DrawYourself(Graphics g)
    		{
    			Console.WriteLine("Triangle");
    			if (g != null)
    			{
    				g.DrawString("Triangle",
    					new Font("Times", Size),
    					new SolidBrush(Color.Black),
    					Position.X, Position.Y);
    			}
    		}
    	}
Hopefully, this sample code demonstrates the challenges of designing an evolving interface. Refactoring the IDrawable interface simplified the task of modifying the interface at the cost of added complexity and class mutability. Have fun, Jeff

##### Send mail to jeff_louie@yahoo.com with questions or comments about this web site. Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007 © Last modified: 11/22/07