paint-brush
Код для интерфейса: все, что вам нужно знатьк@oussamamater
474 чтения
474 чтения

Код для интерфейса: все, что вам нужно знать

к 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(); } }


На самом деле и OpenAiSDK , и RandomAiSDK будут внедрены через конструктор. Таким образом, мы делегируем сложную логику создания экземпляров 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 вообще не должен заботиться о том, кто выполняет эту работу. Ему просто нужно знать, что любая предоставленная реализация сделает это.


Теперь вы можете свободно использовать то или иное.

 $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 сейчас закрыт на модификацию; мы больше не будем трогать код. Это была наша цель с самого начала.


Но он открыт для расширения; если бы мы добавили третьего, четвертого или даже пятого провайдера, нас ничто не остановило бы. Мы можем реализовать интерфейс, и наш класс может использовать его «из коробки», никаких изменений не требуется.

Лисков Замена

Не буду утомлять вас его определением, но, по сути, оно гласит, что вы можете заменять классы ВСЕМИ их подклассами и наоборот. Технически все наши провайдеры AI are-a AIProvider , и их реализации можно менять местами друг на друга, не влияя на корректность ChatBot , последний даже не знает, какого провайдера он использует 😂, так что да, мы уважаем г-жу Лискову .

Инверсия зависимостей

Должен признать, об этом могла бы быть отдельная статья. Но проще говоря, принцип гласит, что вам следует полагаться на абстракции, а не на конкретику, и именно это мы и делаем. Мы зависим от провайдера, а не от конкретного поставщика, такого как Open AI.


Помните: все это потому, что мы написали код для интерфейса.

В конце концов он вам понравится

Всякий раз, когда вы обновляете класс, который, как вы знаете, не следует обновлять, и ваш код становится хакерским из-за операторов if, вам нужен интерфейс. Всегда спрашивайте себя, действительно ли этому классу нужно знать, как? Буду ли я всегда пользоваться услугами этого поставщика услуг? Или драйвер базы данных? Если нет, вы знаете, что делать.


С учетом вышесказанного, просто дайте ему немного времени, и в конечном итоге он вам подойдет .