Callbacks With Interfaces Or Delegates

I'll start like this by directly jumping into a scenario.
You have this one class, which has many methods called by different other classes. For the moment let's not think about those many methods and who calls those.

Focusing on the the matter in hand the requirement is such, that you have to call a method in some other class, which will consume some time for execution. So that method runs that execution in a background thread inside, and only he knows when it finishes. In this scenario you have to give them something to call, may be some reference or some callback method, after the execution of the background thread is done.
What I'm going to discuss now is the ways to do it.

Delegates

First I'll take you on the C#.NET road.
In C# there is a very simple and straight forward way to do this, thanks to "Delegates", which are reference points to the methods. In simple words, in a delegate you can put a method in there, pass it around and call it when ever you like. It also provides features like calling it asynchronously which is not a requirement in our scenario.

So Delegates; creating and using delegates is simple like this.

1. First you declare a Delegate type.
What actually you do here is, create a Delegate type with a particular method signature and then into the variables of that Delegate type, you can assign methods alike to that same declared method signature. Hope my words doesn't confuse you :P
It's simply like you declare a delegate.

delegate <return type of the method> <delegate-name> (<parameter list of the method>)

That's the template and here are couple of examples.

public delegate int MyDelegate (string s);
Into the variables declared with the MyDelegate type, you can assign methods with the signature,
int <method name>(string a).

public delegate void MyDelegate2 (string s, int b, bool z);
Into the variables declared with the MyDelegate2 type, you can assign methods with the signature,
void <method name>(string s, int b, bool z).

2. Second you declare a variable from your Delegate type and assign a method of same signature into it.
MyDelegate2 myDelegate2Obj = methodWithSameSignature;
Here the methodWIthSameSignature() has the same signature of the delegate type and it's obvious that this method should be approachable from the place where myDelegate2Obj is declared.

3. Next you pass the myDelegate2Obj around and call it when ever you like passing the right parameters.
myDelegate2Obj("Hi",15,true);

Using delegates are simple like that.
So what is below is a block of code I implemented using delegates to match our requirement.

public delegate void CallBackType ();

public class MyClass
{
  private void myMethod()
  {
    CallBackType callBackType = this.callBackMethodInMyClass;
  
    HerClass herClass = new HerClass();
    herClass.herTimeTakingMethod(callBackType);
  }
 
  public void callBackMethodInMyClass()
  {
    //This will be called after the time taking execution is completed
  }
}

public class HerClass
{
  private CallBackType callBackType;
 
  public void herTimeTakingMethod(CallBackType callBackType)
  {
    this.callBackType = callBackType;
  
    //Do time taking work in a different thread
    //Thread will call herTimeTakingMethodCompletionEvent() method after completion
    //Example: BackgroundWorker.RunWorkerCompleted Event
  }
 
  private void herTimeTakingMethodCompletionEvent()
  {
    if(this.callBackType != null)
    {
      this.callBackType().
    }
  }
}

myMethod() in MyClass is where actually my execution goes. From there I have to call the herTimeTakingMethod() of her class.
At that point like we learnt earlier how to use delegates, we're passing a delegate referenced to callBackMethodInMyClass into the herTimeTakingMethod() so she can call it when the execution completes inside that method.
Inside herTimeTakingMethod() she assigns the passed parameter to a instance variable, then call it, just as calling a normal method when the time taking execution is finished. When it is done, callBackMethodInMyClass() in my class get called as the delegate was referencing to that.
I think with the above code, it's explains it enough.

For a application with the above code samples, please refer the following link.
https://github.com/nohimys/callbacks-with-delegates-example

Interfaces

Now I'm going to take you on the other road. In Java, you don't have Delegates. But both C# & Java you have interfaces. If you want to learn bit about interfaces, you can look into my other post, Multiple Inheritance with Interfaces.
But in here, all what you should know about interfaces is, after implementing an interface to a class, you get the ability of storing the objects of that class in the reference variables of that implemented interface.

Have you seen something like this? Sometimes as some method parameter, you find some interface type. What that does mean ? You may think what's the point of passing an interface as a parameter, when it's just a fully abstract contract.
Actually what that means is, when you have an interface type as the parameter of a method, "you can pass objects of classes where the particular interface is implemented.". This is the very feature of interfaces that helped replace inheritance.

Anyway, now what we're gonna do is, work on the same above scenario using interfaces.
If you read the Delegate part, this is gonna be really easy. What your requirement is, HerClass from inside there, should be able to call the callBackMethodInMyClass() method in MyClass.

Wait...
Why can't I just declare a MyClass type variable as the parameter to herTimeTakingMethod() in HerClass. Then She can store that as an instance variable and call any method of MyClass, when every she likes.
Can you remember what I told in the beginning?
MyClass has many methods which are called by many other different classes. So if I give her a reference of MyClass, she will get the ability of calling any public method in MyClass.
You know, I'm bit reluctant to know that. She shouldn't get the access to those other methods which should be called by other 'HERS'.. ;) :P

So what I am going to do is, ask her to create a public interface type (Um not gonna touch it. she has to define it in her class, but accessible publicly), and ask her to use it as a parameter for the herTimeTakingMethod()  in HerClass. Then who ever calling that method is bound to a contract to pass an object whose class has implemented that interface.
Then things become very simple. All I have to do is, implement that interface to MyClass. Then definitely MyClass has to implement the methods of that interface, and in this case it would be the callback function which will be called by HerClass.
Then I add the code which need to executed after the time taking process into that implemented methods.
Isn't things are more simple and most importantly cleaner than earlier. There's too many letters to read, so I'll add the code which explains this below.


public class MyClass implements ICallbackMethods
{
  private void myMethod()
  {
    HerClass herClass = new HerClass();
    //this object is passed as this class has implemented the interface
    herClass.herTimeTakingMethod(this);
  }
 
  public void onTimeTakingWorkFinished()
  {
    //This will be called after the time taking execution is completed
  }
}

public class HerClass
{
  private ICallbackMethods iCallbackMethods;

  public void herTimeTakingMethod(ICallbackMethods iCallbackMethods)
  {
    this.iCallbackMethods= iCallbackMethods;
  
    //Do time taking work in a different thread
    //Thread will call herTimeTakingMethodCompletionEvent() method after completion
    //Example: onPostExecution Of AsyncTask in Android
  }
 
  private void herTimeTakingMethodCompletionEvent()
  {
    if(this.iCallbackMethods != null)
    {
      this.iCallbackMethods.onTimeTakingWorkFinished().
    }
  }
 
  public interface ICallbackMethods
  {
    void onTimeTakingWorkFinished();
  }
}


As I said, it's very clean. Every time you want to give some other class the ability of calling methods   of your classes, you can give it through such interfaces. It'll be more cleaner and easy understand.

Cheers :)

Comments

Popular posts from this blog

WPF Dispatcher - Accessing UI Thread From Another Thread

Downgrade NuGet Packages - Visual Studio