I recently found out about Presenter First and read their whitepapers and blogs, etc.
In most of the examples I found, the events are not declared directly on the interface but rather as a method for it. For example,
public interface IPuzzleView
{
void SubscribeMoveRequest(PointDelegate listener);
// vs
event PointDelegate MoveRequest;
}
I don't understand exactly why. I thought I saw a paper/article/blog somewhere that explains the reasoning behind this but I can no longer find it. The said text also contained snippets of unit testing code a开发者_如何学Cs well - I know this because I remember saying to myself, that one of the unit test was incorrect.
UPDATE:
The following is an example for comparison:
public class Collect
{
public static CollectAction<T> Argument<T>(int index,
CollectAction<T>.Collect collectDelegate)
{
CollectAction<T> collect = new CollectAction<T>(index, collectDelegate);
return collect;
}
}
public interface IApplicationView
{
event EventHandler Load;
// or
void SubscribeLoad(Action action);
}
Mockery mockery = new Mockery();
IApplicationView view = mockery.NewMock<IApplicationView>();
IApplicationModel model = mockery.NewMock<IApplicationModel>();
Subscribe style:
Action savedAction = null;
Expect.Once.On(view).Method("SubscribeLoad").Will(
Collect.Argument<Action>(0,
delegate(Action action) { savedAction = action; }));
Expect.Once.On(model).Method("LoadModules");
new ApplicationPresenter(view, model);
savedAction();
mockery.VerifyAllExpectationsHaveBeenMet();
vs. Event:
Expect.Once.On(view).EventAdd("Load", Is.Anything);
Expect.Once.On(model).Method("LoadModules");
new ApplicationPresenter(view, model);
Fire.Event("Load").On(view);
mockery.VerifyAllExpectationsHaveBeenMet();
FYI, the event style above will not work as is since ApplicationPresenter gets garbage-collected right away and the wiring never happens.
The short answer is: Presenter First evolved originally in the days of .NET 1.1 and VS2003, and C# events could be problematic.
Then-current testing/mocking tools didn't support our need to encapsulate event subscription and dispatch. Over time we came to feel that exposing the specific nature of events outside their emitting classes was burdening the client code with too much knowledge of the implementation, which made refactoring difficult.
For published examples, we wanted to avoid associating the Presenter First technique with a language-specific feature. (Eg, Java has no equivalent to C# events or delegates, but that doesn't mean you can't use the Observer pattern.)
I see that events, anonymous delegates and mocking tools have come a long way in the past few years. The next time I pick up a C# project, I will re-evaluate all of my assumptions on "the best way" to handle event subscription and dispatch. The above examples are intriguing.
To summarize our original, perhaps dated, reasons for hiding our use of C# events: - Mocking event subscription wasn't possible in unit tests - Occasionally we'd use a different internal mechanism to handle event subscription/dispatch. This led to inconsistency from one interface to another. - Several times we considered abandoning C# events even internally, as they behaved differently when no subscribers existed. Exposing events externally would have made it much harder to re-implement.
When Jiho Han messaged me with this question, he also inquired about data binding and a more fleshed-out PF example, which I have responded to by publishing a newer, fuller example of Presenter First and elaborating on Adapters.
精彩评论