在编写 GUI 应用程序时,我使用“控制”或“协调”应用程序的顶级类。 顶级类将负责协调诸如初始化网络连接、处理应用程序范围的 UI 操作、加载配置文件等事务。
在 GUI 应用程序控件的某些阶段,将移交给不同的类,例如,主控件从用户通过身份验证后,登录屏幕将转到数据输入屏幕。 不同的类需要使用顶级控件所拥有的对象的功能。 过去我只是将对象传递给从属控件或创建一个界面。 最近,我更改为传递方法委托而不是整个对象,主要原因有两个:
- 在单元测试时模拟方法比类容易得多,
- 通过在类构造函数中准确记录哪些方法从属,使代码更具可读性类正在使用。
下面是一些简化的示例代码:
delegate bool LoginDelegate(string username, string password);
delegate void UpdateDataDelegate(BizData data);
delegate void PrintDataDelegate(BizData data);
class MainScreen {
private MyNetwork m_network;
private MyPrinter m_printer;
private LoginScreen m_loginScreen;
private DataEntryScreen m_dataEntryScreen;
public MainScreen() {
m_network = new Network();
m_printer = new Printer();
m_loginScreen = new LoginScreen(m_network.Login);
m_dataEntryScreen = new DataEntryScreen(m_network.Update, m_printer.Print);
}
}
class LoginScreen {
LoginDelegate Login_External;
public LoginScreen(LoginDelegate login) {
Login_External = login
}
}
class DataEntryScreen {
UpdateDataDelegate UpdateData_External;
PrintDataDelegate PrintData_External;
public DataEntryScreen(UpdateDataDelegate updateData, PrintDataDelegate printData) {
UpdateData_External = updateData;
PrintData_External = printData;
}
}
我的问题是,虽然我更喜欢这种方法,并且它对我来说很有意义,但下一个开发人员将如何找到它? 在示例和开源 C# 代码中,接口是解耦的首选方法,而这种使用委托的方法更倾向于函数式编程。 我是否可能会让后来的开发人员因为这种违反直觉的方法而暗自咒骂?
When writing GUI apps I use a top level class that "controls" or "coordinates" the application. The top level class would be responsible for coordinating things like initialising network connections, handling application wide UI actions, loading configuration files etc.
At certain stages in the GUI app control is handed off to a different class, for example the main control swaps from the login screen to the data entry screen once the user authenticates. The different classes need to use functionality of objects owned by the top level control. In the past I would simply pass the objects to the subordinate controls or create an interface. Lately I have changed to passing method delegates instead of whole objects with the two main reasons being:
- It's a lot easier to mock a method than a class when unit testing,
- It makes the code more readable by documenting in the class constructor exactly which methods subordinate classes are using.
Some simplified example code is below:
delegate bool LoginDelegate(string username, string password);
delegate void UpdateDataDelegate(BizData data);
delegate void PrintDataDelegate(BizData data);
class MainScreen {
private MyNetwork m_network;
private MyPrinter m_printer;
private LoginScreen m_loginScreen;
private DataEntryScreen m_dataEntryScreen;
public MainScreen() {
m_network = new Network();
m_printer = new Printer();
m_loginScreen = new LoginScreen(m_network.Login);
m_dataEntryScreen = new DataEntryScreen(m_network.Update, m_printer.Print);
}
}
class LoginScreen {
LoginDelegate Login_External;
public LoginScreen(LoginDelegate login) {
Login_External = login
}
}
class DataEntryScreen {
UpdateDataDelegate UpdateData_External;
PrintDataDelegate PrintData_External;
public DataEntryScreen(UpdateDataDelegate updateData, PrintDataDelegate printData) {
UpdateData_External = updateData;
PrintData_External = printData;
}
}
My question is that while I prefer this approach and it makes good sense to me how is the next developer that comes along going to find it? In sample and open source C# code interfaces are the preferred approach for decoupling whereas this approach of using delegates leans more towards functional programming. Am I likely to get the subsequent developers swearing under their breath for what is to them a counter-intuitive approach?
发布评论
评论(2)
这是一个有趣的方法。 您可能需要注意两件事:
就像 Philip 提到的那样,当您有很多方法需要定义时,您最终会得到一个很大的构造函数。 这会造成类之间的深度耦合。 多一名或少一名代表将要求所有人修改签名。 您应该考虑将它们设为公共属性并使用一些 DI 框架。
将实现分解到方法级别有时可能过于精细。 使用类/接口,您可以按域/功能对方法进行分组。 如果用委托替换它们,它们可能会混淆并且变得难以阅读/维护。
看来代表的数量是这里的一个重要因素。
It's an interesting approach. You may want to pay attention to two things:
Like Philip mentioned, when you have a lot of methods to define, you will end up with a big constructor. This will cause deep coupling between classes. One more or one less delegate will require everyone to modify the signature. You should consider making them public properties and using some DI framework.
Breaking down the implementation to the method level can be too granular sometimes. With class/interface, you can group methods by the domain/functionality. If you replace them with delegates, they can be mixed up and become difficult to read/maintain.
It seems the number of delegates is an important factor here.
虽然我当然可以看到使用委托而不是接口的积极一面,但我不同意你的两个要点:
“在单元测试时模拟方法比模拟类容易得多”< /em>. 大多数 C# 模拟框架都是围绕模拟类型的想法构建的。 虽然许多人可以模拟方法,但示例和文档(和焦点)通常围绕类型。 使用一种方法模拟接口与方法一样容易或更容易模拟。
“通过在类构造函数中准确记录下级类正在使用哪些方法,使代码更具可读性。”也有它的缺点 - 一旦一个类需要多个方法,构造函数就会变得很大; 一旦从属类需要新的属性或方法,您不仅必须修改接口,还必须将其添加到链上的所有类构造函数中。
我并不是说这无论如何都是一个糟糕的方法 - 传递函数而不是类型确实清楚地说明了您正在做什么,并且可以降低对象模型的复杂性。 然而,在 C# 中,您的下一个开发人员可能会认为这很奇怪或令人困惑(取决于技能水平)。 混合使用面向对象和函数式方法可能至少会引起与您合作的大多数开发人员的注意。
While I can certainly see the positive side of using delegates rather than an interface, I have to disagree with both of your bullet points:
"It's a lot easier to mock a method than a class when unit testing". Most mock frameworks for c# are built around the idea of mocking a type. While many can mock methods, the samples and documentation (and focus) are normally around types. Mocking an interface with one method is just as easy or easier to mock than a method.
"It makes the code more readable by documenting in the class constructor exactly which methods subordinate classes are using." Also has it's cons - once a class needs multiple methods, the constructors get large; and once a subordinate class needs a new property or method, rather than just modifying the interface you must also add it to allthe class constructors up the chain.
I'm not saying this is a bad approach by any means - passing functions rather than types does clearly state what you are doing and can reduce your object model complexity. However, in c# your next developer will probably see this as odd or confusing (depending on skill level). Mixing bits of OO and Functional approaches will probably get a raised eyebrow at the very least from most developers you will work with.