C#接口松散耦合 — 通过Tim Corey(第16课)解释
在课程"C#应用从头到尾"的第16课中,Tim Corey继续构建创建锦标赛表单,但真正的学习目标远不止连接按钮和列表框。 随着Tim完成表单的连接,他在C#中引入了一个核心软件设计概念:用于松耦合的接口。 这节课显示接口不仅仅是一个抽象的学术概念,而是一个实用的工具,用于解决WinForms应用程序中的实际问题。
在这篇文章中,我们深入研究Tim Corey如何解释接口,为什么使用它们,以及它们如何帮助避免紧耦合。 所有的解释、推理和结论都直接来自Tim的演练,使用他的流程、术语和脚本中的示例。
连接表单很简单 — 正确连接它们并不简单
在1:18,Tim开始连接创建奖品和创建团队的UI元素。 他立即指出,这一步可以感觉很吓人,不是因为调用另一个表单很难,而是因为正确获取数据时人们通常会犯错误。
Tim解释说,挑战不是打开另一个表单——那部分很简单。 挑战是如何在不造成长期设计问题的情况下,让一个表单回到另一个表单。 这是定义合同而不是依赖关系开始重要的地方。
紧耦合的诱惑
大约在1:34,Tim明确指出一个常见错误:直接把创建锦标赛表单与创建奖品表单联系在一起。 在这种方法中,一个类确切地知道它在与哪个其他类交谈。
Tim解释这会导致紧耦合,意味着表单直接依赖于彼此。 如果一个表单更改,另一个表单会受到影响。 如果程序的另一个部分后来想要同样的功能,它不能重用它。
他强调,尽管这可能编译并工作,但这不是一个良好的长期设计选择,尤其是在更大的系统或专业环境中。
在编写代码之前考虑步骤
在2:02,Tim停下来,写下步骤而不是直接进入编写代码。 他列出:
调用创建奖品表单
返回一个PrizeModel
- 将其添加到选定的奖品列表中
Tim解释,先写下步骤有助于避免逻辑错误,并使代码的意图清晰。 这种结构化思维在引入接口后变得尤为重要,因为接口定义了必须发生的事情,而不是如何发生。
引用类型以及为何返回值并非总是必要的
大约在4:56时,Tim解释了模型传递的一个重要细节。 他提醒观众,他们正在传递地址,而不是对象的副本。
当通过数据连接器保存奖品时,模型已经填充了其ID。 Tim指出重新返回模型通常是不必要的,因为实例已经被修改。
这进一步说明了为何接口不用于盲目地移动数据——它们用于显示完成和责任,而不是重复。
首先传递模型为何是个坏主意
在6:42,Tim讨论了将PrizeModel传入表单构造函数以便两个表单共享同一实例的想法。
他解释了为何在实际使用中失败:如果用户取消表单,您的列表中会出现一个空的或无效的奖品。Tim展示了仅因为两个类可以共享实例数据并不意味着它们应该这样做。
这个时刻进一步强调了接口定义行为而不是数据存储的概念。
直接传递调用表单更加糟糕
大约在7:46,Tim谈到了另一种常见方法:将整个创建比赛表单传入创建奖品表单并调用如SavePrize的公共方法。
Tim解释说这更糟糕的原因是:
奖品表单现在确切知道哪个类在调用它
其他不相关的类无法复用奖品表单
- 这个类被限定于一个用例
他明确指出这是紧耦合,而这是我们要避免的。
介绍作为契约的接口
在9:01,Tim引入了解决方案:一个接口。
他使用interface关键字创建了一个新的接口,并命名为IPrizeRequester。 Tim提醒观众,接口:
不是一个类
不包含具体方法
- 用于定义契约
该接口包含一个方法:
- PrizeComplete(PrizeModel model)
Tim解释说这方法定义了必须发生的事情,而不是如何发生。
接口成员和责任
在9:40,Tim解释道,无论谁实现这个接口,都同意支持该方法。 接口默认拥有公共成员,它不声明实例数据。
这是Tim明确指出接口定义能力而不是存储的地方。 实现类决定在调用方法时要做什么。
传递接口类型而不是类
在10:19,Tim 修改了创建奖品表单构造函数以接受一个IPrizeRequester而不是具体表单。
他解释说这意味着:
会有人调用表单
表单不知道那是谁
- 唯一的要求是调用者实现了接口
这就是实际中的松耦合。奖品表单依赖于接口类型,而不是特定的类。
存储接口实例以供以后使用
在11:06,Tim在类级别存储接口实例。 他解释说构造函数参数仅在构造函数内部存在,除非存储它们。
这允许奖品表单随后从按钮单击事件内调用PrizeComplete。
回调实现类
在11:49,Tim展示了关键时刻:
callingForm.PrizeComplete(model);他解释说奖品表单现在回调用实现接口的人,并传达说:
"我完成了,这是完成的模型。"
只有在此调用之后,表单才关闭。 这确保只有在创建成功时才添加奖品。
在比赛表单中实现接口
在13:29,Tim切换到创建比赛表单并实现接口。
在13:58,他解释了this关键字,将其描述为当前实例——内存中的实际对象。 通过传递this,表单在通过接口契约移交其地址。
多个接口,一个类
在18:41,Tim介绍了第二个接口:ITeamRequester。
他解释说,虽然一个类只能继承一个基类(比如Form),但它可以实现多个接口。 这允许单个类支持多个不相关的行为,而无需多重继承。
Tim强调接口不带入代码——它们只定义必需的方法。
模式、一致性和错误检测
靠近42:08,Tim反思为何使用模式很重要。 重复相同的基于接口的结构使漏掉的步骤显而易见且调试更容易。
Tim鼓励写下东西,使用一致的模式,而不是试图将一切都放在脑海中。 据他说,好的设计不是关于完美,而是关于清晰性、结构性以及使未来的更改更容易。
结论
在第16课中,Tim Corey使用一个真实的WinForms用例来展示接口如何实现松耦合。 而不是依赖于抽象的例子,他展示了接口如何:
定义契约
解耦类
支持单个类中的多个接口
防止紧耦合
- 提高长期的灵活性
到课程结束时,应用程序不仅可以工作——它被结构化为支持成长、重用和清晰。 Tim的方法使接口在真实世界的C#开发中感觉务实、有目的和必不可少。
要完整、端到端地应用这些接口和松耦合概念,请观看完整的第16课视频,其中每一步都在工作中的C#应用程序内实现、测试和完善。

