Advantages of using delegates?

2019-01-21 21:06发布

I'm looking to implement the Observer pattern in VB.NET or C# or some other first-class .NET language. I've heard that delegates can be used for this, but can't figure out why they would be preferred over plain old interfaces implemented on observers. So,

  • Why should I use delegates instead of defining my own interfaces and passing around references to objects implementing them?
  • Why might I want to avoid using delegates, and go with good ol'-fashioned interfaces?

14条回答
不美不萌又怎样
2楼-- · 2019-01-21 21:28

You're not thinking like a programmer.

The question is, Why would you call a function directly when you could call a delegate?

A famous aphorism of David Wheeler goes: All problems in computer science can be solved by another level of indirection.

I'm being a bit tongue-in-cheek. Obviously, you will call functions directly most of the time, especially within a module. But delegates are useful when a function needs to be invoked in a context where the containing object is not available (or relevant), such as event callbacks.

查看更多
▲ chillily
3楼-- · 2019-01-21 21:29

I'm repeating an answer I gave to this question.

I've always like the Radio Station metaphor.

When a radio station wants to broadcast something, it just sends it out. It doesn't need to know if there is actually anybody out there listening. Your radio is able to register itself with the radio station (by tuning in with the dial), and all radio station broadcasts (events in our little metaphor) are received by the radio who translates them into sound.

Without this registration (or event) mechanism. The radio station would have to contact each and every radio in turn and ask if it wanted the broadcast, if your radio said yes, then send the signal to it directly.

Your code may follow a very similar paradigm, where one class performs an action, but that class may not know, or may not want to know who will care about, or act on that action taking place. So it provides a way for any object to register or unregister itself for notification that the action has taken place.

查看更多
狗以群分
4楼-- · 2019-01-21 21:30

There are two places that you could use delegates in the Observer pattern. Since I am not sure which one you are referring to, I will try to answer both.

The first is to use delegates in the subject instead of a list of IObservers. This approach seems a lot cleaner at handling multicasting since you basically have

private delegate void UpdateHandler(string message);
private UpdateHandler Update;

public void Register(IObserver observer)
{
    Update+=observer.Update;
}

public void Unregister(IObserver observer)
{
    Update-=observer.Update;
}

public void Notify(string message)
{
    Update(message);
}

instead of

public Subject()
{
    observers = new List<IObserver>();
}

public void Register(IObserver observer)
{
    observers.Add(observer);
}

public void Unregister(IObserver observer)
{
    observers.Remove(observer);
}

public void Notify(string message)
{
    // call update method for every observer
    foreach (IObserver observer in observers)
    {
        observer.Update(message);
    }
}

Unless you need to do something special and require a reference to the entire IObserver object, I would think the delegates would be cleaner.

The second case is to use pass delegates instead of IObervers for example

public delegate void UpdateHandler(string message);
private UpdateHandler Update;

public void Register(UpdateHandler observerRoutine)
{
    Update+=observerRoutine;
}

public void Unregister(UpdateHandler observerRoutine)
{
    Update-=observerRoutine;
}

public void Notify(string message)
{
    Update(message);
}

With this, Observers don't need to implement an interface. You could even pass in a lambda expression. This changes in the level of control is pretty much the difference. Whether this is good or bad is up to you.

查看更多
地球回转人心会变
5楼-- · 2019-01-21 21:37

Look at it the other way. What advantage would using a custom interface have over using the standard way that is supported by the language in both syntax and library?

Granted, there are cases where it a custom-tailored solution might have advantages, and in such cases you should use it. In all other cases, use the most canonical solution available. It's less work, more intuitive (because it's what users expect), has more support from tools (including the IDE) and chances are, the compiler treats them differently, resulting in more efficient code.

Don't reinvent the wheel (unless the current version is broken).

查看更多
成全新的幸福
6楼-- · 2019-01-21 21:42

When you can directly call a method, you don't need a delegate.

A delegate is useful when the code calling the method doesn't know/care what the method it's calling is -- for example, you might invoke a long-running task and pass it a delegate to a callback method that the task can use to send notifications about its status.

Here is a (very silly) code sample:

enum TaskStatus
{
   Started,
   StillProcessing,
   Finished
}

delegate void CallbackDelegate(Task t, TaskStatus status);

class Task
{
    public void Start(CallbackDelegate callback)
    {
        callback(this, TaskStatus.Started);

        // calculate PI to 1 billion digits
        for (...)
        {
            callback(this, TaskStatus.StillProcessing);
        }

        callback(this, TaskStatus.Finished);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Task t = new Task();
        t.Start(new CallbackDelegate(MyCallbackMethod));
    }

    static void MyCallbackMethod(Task t, TaskStatus status)
    {
        Console.WriteLine("The task status is {0}", status);
    }
}

As you can see, the Task class doesn't know or care that -- in this case -- the delegate is to a method that prints the status of the task to the console. The method could equally well send the status over a network connection to another computer. Etc.

查看更多
可以哭但决不认输i
7楼-- · 2019-01-21 21:42

A delegate is, in effect, passing around a reference to a method, not an object... An Interface is a reference to a subset of the methods implemented by an object...

If, in some component of your application, you need access to more than one method of an object, then define an interface representing that subset of the objects' methods, and assign and implement that interface on all classes you might need to pass to this component... Then pass the instances of these classes by that interface instead of by their concrete class..

If, otoh, in some method, or component, all you need is one of several methods, which can be in any number of different classes, but all have the same signature, then you need to use a delegate.

查看更多
登录 后发表回答