使用委托代替接口进行解耦。好主意?

时间:2009-05-19 01:55:05

标签: c# unit-testing functional-programming readability decoupling

在编写GUI应用程序时,我使用“控制”或“协调”应用程序的顶级类。顶级类将负责协调诸如初始化网络连接,处理应用程序范围的UI操作,加载配置文件等内容。

在GUI app控件的某些阶段,切换到另一个类,例如,一旦用户进行身份验证,主控件就会从登录屏幕切换到数据输入屏幕。不同的类需要使用顶级控件拥有的对象的功能。在过去,我只是将对象传递给从属控件或创建一个接口。最近我改为传递方法委托而不是整个对象,主要有两个原因:

  • 在单元测试时,模拟方法要比类更容易,
  • 通过在类构造函数中准确地记录从属类正在使用哪些方法,使代码更具可读性。

下面是一些简化的示例代码:

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#代码接口是解耦的首选方法,而这种使用委托的方法更倾向于函数式编程。我是否有可能让后来的开发人员在他们的呼吸下咒骂他们对他们采取反直觉的做法?

2 个答案:

答案 0 :(得分:2)

这是一种有趣的方法。您可能需要注意两件事:

  1. 就像Philip提到的那样,当你有很多方法要定义时,你最终会得到一个很大的构造函数。这将导致类之间的深度耦合。一个或多一个代表将要求每个人修改签名。您应该考虑将它们作为公共属性并使用一些DI框架。

  2. 将实现细分为方法级别有时可能过于细化。使用类/接口,您可以按域/功能对方法进行分组。如果用代表替换它们,它们可能会混淆并变得难以阅读/维护。

  3. 看来代表人数是一个重要因素。

答案 1 :(得分:1)

虽然我当然可以看到使用代表而不是界面的积极方面,但我不得不同意你的两个要点:

  • “在单元测试”时,模拟方法要比类更容易。 c#的大多数模拟框架都是围绕模拟类型的想法而构建的。虽然许多人可以模拟方法,但样本和文档(以及焦点)通常都是类型。使用一种方法模拟接口与模拟方法一样容易或更容易。

  • “它通过在类构造函数中准确地记录下级类正在使用哪些方法来使代码更具可读性。”还有它的缺点 - 一旦类需要多个方法,构造函数就会得到大;一旦下属类需要一个新的属性或方法,而不仅仅是修改接口,你还必须将它添加到链上的所有类构造函数。

我并不是说这是一种糟糕的方法 - 传递函数而不是类型确实清楚地说明了你在做什么并且可以减少对象模型的复杂性。但是,在c#中,您的下一个开发人员可能会将此视为奇怪或混乱(取决于技能级别)。混合使用OO和功能方法可能会让大多数开发人员大开眼界。