Tight coupling
Once upon a time, in a strange land in the south, there was a worker named Peter, who was very diligent and always obedient to his boss. But his boss was a miserly man who never trusted anyone and insisted on knowing Peter's work at all times to keep him from slacking off. But Peter did not want the boss to stay in his office and stare at him, so he made a promise to the boss: whenever I get a little progress in my work, I'll let you know in time. Peter uses the "type of reference" periodically (the original: "Typed reference") is delegate?? "Callback" his boss to fulfill his promise as follows:
class Worker
{
public void Advise (Boss boss) {_boss = boss;}
public void DoWork ()
{
Console.WriteLine ("Work: Start of work");
if (_boss!= null) _boss. Workstarted ();
Console.WriteLine ("Work: Work in progress");
if (_boss!= null) _boss. Workprogressing ();
Console.WriteLine ("Work: Work Completed");
if (_boss!= null)
{
int grade = _boss. Workcompleted ();
Console.WriteLine ("Worker's work score =" + grade);
}
}
private Boss _boss;
}
class Boss
{
public void workstarted () {}
public void Workprogressing () {}
public int workcompleted ()
{
Console.WriteLine ("Time is almost 1");
return 2;
}
}
Class Universe
{
static void Main ()
{
worker Peter = new Worker ();
Boss Boss = new Boss ();
Peter. Advise (boss);
Peter. DoWork ();
Console.WriteLine ("Main: Worker work completed");
Console.ReadLine ();
}
}
Interface
Now, Peter became a special man, not only tolerant of stingy bosses, but also closely connected with the universe around him, so that he thought the universe was interested in the progress of his work. Unfortunately, he must also add a special callback function to the universe to advise to his boss and the universe to report work progress. Peter wanted to separate the list of potential announcements from the implementation of these notices, so he decided to detach the method into an interface that would cause other problems that would result from. NET delegate to resolve):
Interface Iworkerevents
{
void workstarted ();
void workprogressing ();
int workcompleted ();
}
class Worker
{
public void Advise (iworkerevents events)
{
_events = events;
}
public void DoWork ()
{
Console.WriteLine ("Work: Start of work");
if (_events!= null) _events. Workstarted ();
Console.WriteLine ("Work: Work in progress");
if (_events!= null) _events. Workprogressing ();
Console.WriteLine ("Work: Work Completed");
if (_events!= null)
{
int grade = _events. Workcompleted ();
Console.WriteLine ("Worker's work score =" + grade);
}
}
private iworkerevents _events;
}
class Boss:iworkerevents
{
public void workstarted () {}
public void Workprogressing () {}
public int workcompleted ()
{
Console.WriteLine ("Time is almost 1");
return 3;
}
}
. NET delegate
Unfortunately, whenever Peter is busy communicating with his boss through the implementation of the interface, he has no chance to inform the universe in time. At the very least, he should ignore the reference from his boss in the distance so that other iworkerevents objects can get his work report. ("At least him" D abstracted the reference of his boss far Moz from him and so this others who implemented the iworkerevents in Terface could be notified's his work progress "in the exact words, do not understand what it means.
His boss still complains badly. Peter's boss roared, "Why do you bother me at the beginning of work and in the course of work?" I don't care about these events. You not only forced me to implement these methods, but also wasted my valuable working hours to deal with your events, especially when I was out. Can you stop bothering me? ”
Peter realizes that the interface is useful in many cases, but when used as an event, "granularity" is not good enough. He wanted to be notified only when others wanted it, so he decided to separate the methods of the interface into separate delegates, each of which was like a small interface method:
delegate void workstarted ();
delegate void Workprogressing ();
delegate int workcompleted ();
class Worker
{
public void DoWork ()
{
Console.WriteLine ("Work: Start of work");
if (started!= null) started ();
Console.WriteLine ("Work: Work in progress");
if (progressing!= null) progressing ();
Console.WriteLine ("Work: Work Completed");
if (completed!= null)
{
int grade = completed ();
Console.WriteLine ("Worker's work score =" + grade);
}
}
public workstarted started;
public workprogressing progressing;
public workcompleted completed;
}
class Boss
{
public int workcompleted ()
{
Console.WriteLine ("Decoupled ...");
return 4;
}
}
Class Universe
{
static void Main ()
{
worker Peter = new Worker ();
Boss Boss = new Boss ();
peter.completed = new workcompleted (boss. workcompleted);
Peter. DoWork ();
Console.WriteLine ("Main: Worker work completed");
Console.ReadLine ();
}
}
Static supervisor
In this way, Peter will not bother his boss about the things his boss doesn't want, but he hasn't put the universe on his listener list yet. Because the universe is an inclusive entity, it does not seem appropriate to use an instance method delegate (Imagine how much resources it would take to instantiate a "universe" ...), so Peter would need to be able to hook up static delegates, and the delegates would support this very well:
Class Universe
{
static void Workerstartedwork ()
{
Console.WriteLine ("Universe notices worker starting work");
}
static int workercompletedwork ()
{
Console.WriteLine ("Universe pleased with worker ' s work");
return 7;
}
static void Main ()
{
worker Peter = new Worker ();
Boss Boss = new Boss ();
peter.completed = new workcompleted (boss. workcompleted);
peter.started = new workstarted (universe.workerstartedwork);
peter.completed = new workcompleted (universe.workercompletedwork);
Peter. DoWork ();
Console.WriteLine ("Main: Worker work completed");
Console.ReadLine ();
}
}
Event
Unfortunately, the universe is too busy to pay attention to the individual in it, and it can replace Peter Boss's Commission with its own delegate. This is an unconscious side effect of making the delegate field of Peter's worker class public. Similarly, if Peter's boss is impatient, he can also decide to inspire Peter's Commission (really a rude boss):
//Peter ' s boss taking matters into his own hands
if (peter.completed!= null) peter.completed ();
Peter didn't want this to happen, and he realized that it was necessary to give each delegate a "registration" and "Anti-registration" feature, so that the listener could add and remove delegates themselves, while not emptying the entire list, and could not inspire Peter's events. Instead of implementing these features, Peter uses the event keyword to have the C # compiler build These methods for him:
Class Worker
{
...
public event workstarted started;
public event workprogressing progressing;
public event workcompleted completed;
}
Peter knows that the event keyword wraps a property outside of the delegate, allowing C # customers to add and remove them through the + = and-= operators, forcing his boss and the universe to use events correctly.
static void Main ()
{
worker Peter = new Worker ();
Boss Boss = new Boss ();
peter.completed + = new Workcompleted (boss. workcompleted);
peter.started + = new workstarted (universe.workerstartedwork);
peter.completed + = new workcompleted (universe.workercompletedwork);
Peter. DoWork ();
Console.WriteLine ("Main: Worker work completed");
Console.ReadLine ();
}
"Harvest" All results
By this time, Peter could finally give a breath, he succeeded in satisfying the needs of all listeners while avoiding the tight coupling with specific implementations. But he noticed that his boss and the universe were scoring for his work, but he only received a score. Faced with multiple listeners, he wanted to "harvest" all the results, so he went deep into the agent, polling the listener list, manually calling:
public void DoWork ()
{
...
Console.WriteLine ("Work: Work Completed");
if (completed!= null)
{
foreach (workcompleted WC in completed. Getinvocationlist ())
{
int grade = WC ();
Console.WriteLine ("Worker's work score =" + grade);
}
}
}
Asynchronous notification: Inspire & Forget
At the same time, his boss and the universe are busy dealing with other things, that is to say, the events they have spent on Peter's rating have become very long:
class Boss
{
public int workcompleted ()
{
System.Threading.Thread.Sleep (3000);
Console.WriteLine ("Decoupled ...");
return 6;
}
}
Class Universe
{
static int workercompletedwork ()
{
System.Threading.Thread.Sleep (4000);
Console.WriteLine ("Universe is pleased with worker ' s work");
return 7;
}
...
}
Unfortunately, Peter had to wait for him to rate himself each time he notified a listener, and now these notices cost him too much work. So he decided to forget the score and just fire the event asynchronously:
public void DoWork ()
{
...
Console.WriteLine ("Work: Work Completed");
if (completed!= null)
{
foreach (workcompleted WC in completed. Getinvocationlist ())
{
WC. BeginInvoke (null, NULL);
}
}
}
Asynchronous notification: Polling
This allows Peter to notify his listeners and then immediately return to work to let the process line pool invoke these proxies. Over time, Peter discovered that he had lost feedback on his work and that listening to others ' praise was as important as hard work, so he fired the event asynchronously, but periodically polled to get the available score.
public void DoWork ()
{
...
Console.WriteLine ("Work: Work Completed");
if (completed!= null)
{
foreach (workcompleted WC in completed. Getinvocationlist ())
{
IAsyncResult res = WC. BeginInvoke (null, NULL);
while (!res. iscompleted) System.Threading.Thread.Sleep (1);
int grade = WC. EndInvoke (RES);
Console.WriteLine ("Worker's work score =" + grade);
}
}
}
Asynchronous notification:. NET delegate
Unfortunately, Peter has come back to the beginning to avoid the situation, for example, the boss stood behind him staring at his work. So he decided to use his own delegate as a notification of the completion of the asynchronous delegate he invoked, allowing him to return to work at once, but could still be notified when he was graded by someone else for his work:
public void DoWork ()
{
...
Console.WriteLine ("Work: Work Completed");
if (completed!= null)
{
foreach (workcompleted WC in completed. Getinvocationlist ())
{
WC. BeginInvoke (New AsyncCallback (workgraded), WC);
}
}
}
private void workgraded (IAsyncResult res)
{
workcompleted WC = (workcompleted) Res. asyncstate;
int grade = WC. EndInvoke (RES);
Console.WriteLine ("Worker's work score =" + grade);
}
Happiness in the Universe
Peter, his boss and the universe were finally satisfied. Peter's boss and the universe can receive notification of events of interest to them, reducing the burden of implementation and non-essential round-trip "travel". Peter can notify them, regardless of how long it takes them to return from the method of intent, while at the same time can get his results asynchronously. Peter knows that this is not very simple, because when he fires an event asynchronously, the method is executed in another thread, and so does the notification that Peter's purpose method completes. But Mike and Peter are good friends and he is very familiar with threading things that can provide guidance in this field.
They live happily ever after ... < >