paint-brush
接口代码:你需要知道的一切经过@oussamamater
351 讀數
351 讀數

接口代码:你需要知道的一切

经过 Oussama Mater7m2024/06/18
Read on Terminal Reader

太長; 讀書

“为接口编写代码”对我来说毫无意义。我质疑创建接口然后实现它的必要性。我如何确定何时何地使用这些接口?如果您遇到这种情况,请记住我们都遇到过这种情况。让我们帮助您了解为什么需要“为接口编写代码”。
featured image - 接口代码:你需要知道的一切
Oussama Mater HackerNoon profile picture

随着你对编程越来越认真,你不可避免地会在视频、书籍或文章中看到“为接口编写代码”这句话。但对我来说,这句话毫无意义。我质疑创建接口然后实现它的必要性。我如何确定何时何地使用这些接口?


每当我看教程或读文章时,他们都会解释什么是接口,“它是一个没有实现的类”,我会说“嗯,谢谢😏”。我的意思是,我已经知道了;我真正想知道的是为什么以及何时使用它。


我记得有一天我在 Discord 社区上提问,其中一位资深人士简单地说:“别担心;你最终会明白的”,确实如此,虽然花了一些时间,但确实如此。如果你遇到这种情况,要知道我们都经历过;让我们帮助你理解为什么你需要为接口编写代码

让我们写一些代码

由于人工智能正在接管一切,每个人都为之疯狂,我们不想错过这个机会。我们想将它添加到我们的网站中,一个可以回答有关我们产品的问题的小型聊天机器人就可以做到这一点。


我将使用 PHP 作为示例;您可以随意使用任何您熟悉的语言。重要的是概念。


我们的聊天机器人可以像这样简单:

 <?php class ChatBot { public function ask(string $question): string { $client = new OpenAi(); $response = $client->ask($question); return $response; } }

有一个方法ask() ,它使用OpenAI SDK连接到他们的 API,提出问题,然后简单地返回答案。


我们现在可以开始使用我们的聊天机器人

$bot = new ChatBot(); $response = $bot->ask('How much is product X'); // The product costs $200.


到目前为止,实施效果不错,运行正常,项目已部署并投入使用。但我们不能否认,我们的聊天机器人严重依赖 Open AI API;我相信您也同意这一点。


现在,让我们考虑一下 Open AI 价格翻倍并继续上涨的情况,我们有什么选择?我们要么接受命运,要么寻找另一个 API。第一个选择很简单,我们只需继续付钱,而第二个选择并不像听起来那么简单。新的提供商可能会有自己的 API 和 SDK;我们将不得不对最初为 Open AI 设计的所有类、测试和相关组件进行更新,这是一项艰巨的工作。


这也引发了担忧;如果新 API 在准确性方面不符合我们的期望或增加了停机时间怎么办?如果我们只想同时尝试不同的提供商怎么办?例如,为我们的订阅客户端提供 OpenAI 客户端,同时为访客使用更简单的 API?您可以看到这有多复杂,您知道为什么吗?因为我们的代码设计得很差。


我们没有愿景;我们只是选择了一个 API,并完全依赖它及其实现。现在,“代码到接口”原则可以让我们免于所有这些。如何做到?让我们看看。


让我们从创建一个界面开始:

 <?php interface AIProvider { public function ask(string $question): string; }


我们有接口,或者我喜欢称之为契约。让我们实现它或为它编写代码。

 <?php class OpenAi implements AIProvider { public function ask(string $question): string { $openAiSdk = new OpenAiSDK(); $response = $openAiSdk->ask($question); return "Open AI says: " . $response; } } class RandomAi implements AIProvider { public function ask(string $question): string { $randomAiSdk = new RandomAiSDK(); $response = $randomAiSdk->send($question); return "Random AI replies: " . $response->getResponse(); } }


实际上, OpenAiSDKRandomAiSDK都将通过构造函数注入。这样,我们将复杂的实例化逻辑委托给DI 容器,这一概念称为控制反转。这是因为每个提供商通常都需要某些配置。


我们现在有两个提供商可以用来回答问题。无论他们如何实现,我们都有信心,当提出问题时,他们会连接到他们的 API 并做出回应。他们必须遵守合同AIProvider


现在,在我们的ChatBot中,我们可以执行以下操作

class ChatBot { private AIProvider $client; // A dependency can be injected via the constructor public function __construct(AIProvider $client) { $this->client = $client; } // It can also be set via a setter method public function setClient(AIProvider $client): void { $this->client = $client; } public function ask(string $question): string { return $this->client->ask($question); } }


请注意,该示例旨在演示注入依赖项(在本例中为AIProvider )的多种方式。您不需要同时使用构造函数和设置器。


您可以看到我们做了一些调整;我们不再依赖 OpenAI,您也找不到任何对它的引用。相反,我们依赖合同/接口。而且,不知何故,我们可以在现实生活中与这个例子联系起来;我们都至少曾经是ChatBot


想象一下购买太阳能电池板系统。该公司承诺派技术人员来安装它,并向您保证,无论他们派哪位员工来,工作都会完成,最终您将安装好太阳能电池板。所以,你并不关心他们派乔希还是乔治来。他们可能不同,一个比另一个更好,但他们都签订了安装太阳能电池板的合同。


他们不会说,你知道我在修理你的电视,而是公司要求他们做指定的工作。RandomAi 和OpenAi都是AIProvider的员工;你问一个问题,他们会给出答案。就像你不关心谁安装面板一样, ChatBot也不应该关心RandomAi做这项工作。它只需要知道提供的任何实现都会完成这项工作。


现在,您可以自由使用其中一个。

 $bot = new ChatBot(); // For subscribed users $bot = new ChatBot(new OpenAi()); $response = $bot->ask('How much is Product X'); // Open AI says: 200$ // For guests $bot->setClient(new RandomAi()); $response = $bot->ask('How much is Product X'); // Random AI replies: 200$

现在,您可以灵活地更改整个 API 提供程序,并且您的代码将始终保持相同的行为。您无需更改任何内容,因为您已针对接口进行编码,因此我们之前提出的所有问题都不再是问题。

总是有奖金

在我们的示例中,通过对接口进行编码,我们也遵守了SOLID原则中的三个,甚至在我们不知情的情况下,让我详细说明一下。


我不会详细阐述;每个原则都可以写一篇很长的文章。这只是一个简短的解释,以展示我们通过编写接口代码所获得的收获。

开放封闭原则

我们尊重的第一条原则是开放封闭原则,即代码应该对扩展开放,对修改封闭。虽然听起来很有挑战性,但你已经做到了。想想看, ChatBot现在对修改封闭了;我们不会再碰代码了。这是我们从一开始就设定的目标。


但是,它是开放的,可以扩展;如果我们要添加第 3、第 4 甚至第 5 个提供程序,没有什么可以阻止我们。我们可以实现接口,并且我们的类可以开箱即用,无需进行任何更改。

里氏替换

我不会用它的定义来烦你,但基本上,它表明你可以用所有子类替换类,反之亦然。从技术上讲,我们所有的 AI 提供者are-a AIProvider ,它们的实现可以相互交换,而不会影响ChatBot的正确性,后者甚至不知道它正在使用哪个提供者 😂,所以是的,我们尊重 Liskov 女士。

依赖反转

我必须承认,这可以写一篇文章。但简单地说,该原则表明你应该依赖抽象而不是具体,这正是我们正在做的。我们依赖的是提供商,而不是像 Open AI 这样的特定提供商。


请记住,所有这一切,都是因为我们对接口进行了编码。

它最终会为你打开

每当您更新一个您知道不应该更新的类时,并且您的代码因 if 语句而变得混乱,您就需要一个接口。总是问自己,这个类真的需要知道如何做吗?我会永远使用这个服务提供商吗?还是数据库驱动程序?如果不是,您就知道该怎么做了。


话虽如此,只要给它一些时间,它最终会为你打开思路