Saturday, June 05, 2010

Program To The Interface

One of the biggest benefits of using Interfaces (in my opinion) is to be able to "program to the Interface", as they say. Let me explain with a real-world example:

Suppose I have created this Interface:

public interface IFillFromFinder
{
void FillListView(DataSet dsList);
void ClearListView();
}

Now, suppose I have a class that contains a ListView and implements the Interface:

public class MySearchClass : MyUserControl, IFillFromFinder
{
#region Declarations

protected ListView oListView;
protected MyFinderForm oFinder;

#endregion

#region Methods

public void Search(ListView listView)
{
this.oListView = listview;
this.ClearListView();

this.oFinder = new MyFinderForm(this);
oFinder.ShowDialog();
}

// Interface methods to implement
public void ClearListView()
{
// code here for clearing listview
}

public void FillListView(DataSet dsList)
{
// code here for filling listview
}

#endregion
}

As you can see, this class calls a Finder dialog Form, that gathers information from the User and performs a query against the backend data. If the Finder Dialog has been called from a control that implements this Interface (as in the above call from the Search() method), then it can also fill that control's ListView object by calling the methods on the Interface.

Here's the relevant part of my Finder Dialog. Note that the oListControl is defined using the Interface. MyFinderForm needs to know absolutely nothing else about what's calling it, other than that it implements the IFillFromFinder interface.

public class MyFinderForm : MyDialogForm    
{
#region Declarations

public MyListDataSet oData = new MyListDataSet();
protected IFillFromFinder oListControl = null;

#endregion

#region Constructors

public MyFinderForm(IFillFromFinder CallingControl)
{
this.oListControl = CallingControl;
InitializeComponent();
}

public MyFinderForm()
{
InitializeComponent();
}

#endregion

#region Events

private void cmdOK_Click(object sender, System.EventArgs e)
{
this.FillDataSet();

// If this dialog form was called by a class that implemented IFillFromFinder,
// then call call the Interface method to fill the ListView.
if (this.oListControl != null)
{
if (this.chkReplace.Checked == true)
this.oListControl.ClearListView();
this.oListControl.FillListView(this.oData);
}
}


#endregion
}

Here's another good example. Suppose I need to perform some kind of action, or access a property, on a Control on my Form, but not all Controls on my Form have the appropriate method or property. Interfaces come in handy for this, as these two examples illustrate:

foreach (IMyControl control in this.Controls)
{
control.MyMethod();
control.MyProperty = "whatever";
}

-or-

if (SomeControl is IMyControl)
{
((IMyControl)SomeControl).MyMethod();
((IMyControl)SomeControl).MyProperty = "whatever";
}

I hope this sort of helps explain interfaces by using a real world example.