paint-brush
Viết mã cho giao diện: Mọi thứ bạn cần biếttừ tác giả@oussamamater
482 lượt đọc
482 lượt đọc

Viết mã cho giao diện: Mọi thứ bạn cần biết

từ tác giả Oussama Mater7m2024/06/18
Read on Terminal Reader

dài quá đọc không nổi

"Mã cho giao diện" không bao giờ có ý nghĩa đối với tôi. Tôi đặt câu hỏi về sự cần thiết phải tạo một giao diện và sau đó triển khai nó. Làm cách nào để xác định thời điểm và địa điểm sử dụng các giao diện này? Nếu bạn đang trải qua điều này, hãy biết rằng tất cả chúng ta đều đã từng trải qua điều đó. Hãy giúp bạn hiểu lý do tại sao bạn cần "Code to Interface".
featured image - Viết mã cho giao diện: Mọi thứ bạn cần biết
Oussama Mater HackerNoon profile picture

Khi bạn nghiêm túc hơn trong việc lập trình, bạn chắc chắn sẽ gặp phải cụm từ "Mã cho giao diện", trong video, sách hoặc bài viết. Và nó không bao giờ có ý nghĩa với tôi. Tôi đặt câu hỏi về sự cần thiết phải tạo một giao diện và sau đó triển khai nó. Làm cách nào để xác định thời điểm và địa điểm sử dụng các giao diện này?


Bất cứ khi nào tôi xem hướng dẫn hoặc đọc một bài viết, họ sẽ giải thích giao diện là gì, "Đó là một lớp không cần triển khai" và tôi nói "Ơmm, cảm ơn 😏". Ý tôi là, tôi đã biết điều đó rồi; điều tôi thực sự muốn biết là tại sao và khi nào nên sử dụng nó.


Tôi nhớ một ngày nọ, tôi hỏi cộng đồng Discord và một trong những tiền bối chỉ nói: "Đừng lo lắng; cuối cùng nó sẽ phù hợp với bạn" và nó đã thành công, phải mất một thời gian nhưng nó đã thành công. Nếu bạn đang trải qua điều này, hãy biết rằng tất cả chúng ta đều đã từng trải qua; hãy giúp bạn hiểu lý do tại sao bạn cần viết mã cho một giao diện .

Hãy viết một số mã

Vì AI đang tiếp quản và mọi người đang mất hứng thú với nó nên chúng tôi không muốn đến bữa tiệc muộn. Chúng tôi muốn thêm nó vào trang web của mình, một chatbot nhỏ trả lời các câu hỏi về sản phẩm của chúng tôi sẽ làm điều đó.


Tôi sẽ sử dụng PHP làm ví dụ của mình; hãy thoải mái sử dụng bất kỳ ngôn ngữ nào bạn cảm thấy thoải mái. Điều quan trọng là khái niệm.


Chatbot của chúng tôi có thể đơn giản như thế này:

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

Có một phương thức duy nhất ask() , sử dụng SDK OpenAI để kết nối với API của họ, đặt câu hỏi và sau đó chỉ cần trả lời phản hồi.


Bây giờ chúng ta có thể bắt đầu sử dụng chatbot của mình

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


Cho đến nay, quá trình triển khai có vẻ ổn, hoạt động như mong đợi và dự án đã được triển khai và sử dụng. Tuy nhiên, chúng tôi không thể phủ nhận rằng chatbot của chúng tôi phụ thuộc rất nhiều vào API Open AI; Tôi chắc chắn bạn đồng ý.


Bây giờ, hãy xem xét một kịch bản trong đó giá Open AI tăng gấp đôi và tiếp tục tăng, chúng ta có những lựa chọn nào? Chúng tôi chấp nhận số phận của mình hoặc tìm kiếm một API khác. Tùy chọn đầu tiên rất dễ dàng, chúng tôi chỉ cần tiếp tục trả tiền cho họ và tùy chọn thứ 2 không đơn giản như người ta tưởng. Nhà cung cấp mới có thể sẽ có API và SDK riêng; chúng tôi sẽ phải cập nhật tất cả các lớp, bài kiểm tra và các thành phần liên quan được thiết kế ban đầu cho AI mở, đó là rất nhiều công việc.


Điều này cũng gây lo ngại; điều gì sẽ xảy ra nếu API mới không đáp ứng mong đợi của chúng tôi về độ chính xác hoặc tăng thời gian ngừng hoạt động? Điều gì sẽ xảy ra nếu chúng ta muốn thử nghiệm đồng thời với các nhà cung cấp khác nhau? Ví dụ: cung cấp cho khách hàng đã đăng ký của chúng tôi ứng dụng khách OpenAI trong khi sử dụng API đơn giản hơn cho khách? Bạn có thể thấy điều này có thể phức tạp như thế nào và bạn biết tại sao không? Bởi vì mã của chúng tôi được thiết kế kém.


Chúng tôi không có tầm nhìn; chúng tôi vừa chọn một API và hoàn toàn phụ thuộc vào nó cũng như việc triển khai nó. Bây giờ, nguyên tắc "Mã giao diện" sẽ cứu chúng ta khỏi tất cả những điều này. Làm sao? Hãy xem nào.


Hãy bắt đầu với việc tạo một giao diện:

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


Chúng tôi có giao diện của mình, hay tôi muốn gọi nó là một hợp đồng. Hãy triển khai nó hoặc viết mã cho nó.

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


Trên thực tế, cả OpenAiSDKRandomAiSDK đều sẽ được đưa vào thông qua hàm tạo. Bằng cách này, chúng tôi ủy quyền logic khởi tạo phức tạp cho vùng chứa DI , một khái niệm được gọi là đảo ngược điều khiển . Điều này là do mỗi nhà cung cấp thường yêu cầu một số cấu hình nhất định.


Hiện tại chúng tôi có hai nhà cung cấp mà chúng tôi có thể sử dụng để trả lời các câu hỏi. Bất kể cách triển khai của họ như thế nào, chúng tôi tin tưởng rằng khi được đưa ra một câu hỏi, họ sẽ kết nối với API của mình và trả lời câu hỏi đó. Họ phải tuân thủ hợp đồng AIProvider .


Bây giờ, trong ChatBot , chúng ta có thể làm như sau

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


Xin lưu ý rằng ví dụ này nhằm mục đích minh họa nhiều cách bạn có thể đưa vào một phần phụ thuộc, trong trường hợp này là AIProvider . Bạn không bắt buộc phải sử dụng cả hàm tạo và hàm setters.


Bạn có thể thấy chúng tôi đã thực hiện một số điều chỉnh; chúng tôi không còn phụ thuộc vào OpenAI nữa và bạn sẽ không tìm thấy bất kỳ tài liệu tham khảo nào về nó. Thay vào đó, chúng tôi phụ thuộc vào hợp đồng/giao diện. Và bằng cách nào đó, chúng ta có thể liên tưởng đến ví dụ này trong đời thực; tất cả chúng ta đều đã từng là ChatBot ít nhất một lần.


Hãy tưởng tượng mua một hệ thống bảng điều khiển năng lượng mặt trời. Công ty hứa sẽ cử kỹ thuật viên đến lắp đặt, đảm bảo với bạn rằng bất kể họ cử nhân viên nào, công việc sẽ hoàn thành và cuối cùng bạn sẽ lắp đặt được bảng điều khiển của mình. Vì vậy, bạn không thực sự quan tâm liệu họ cử Josh hay George. Chúng có thể khác nhau, cái này tốt hơn cái kia, nhưng cả hai đều được ký hợp đồng lắp đặt các tấm pin.


Họ sẽ không như thế, bạn biết tôi đang sửa TV cho bạn mà thay vào đó, họ bị công ty bắt buộc phải làm công việc được chỉ định. Cả RandomAiOpenAi đều đóng vai trò là nhân viên của AIProvider ; bạn đặt câu hỏi và họ sẽ đưa ra câu trả lời. Giống như bạn không quan tâm đến việc ai cài đặt bảng điều khiển, ChatBot không nên quan tâm đến việc ai thực hiện công việc. Nó chỉ cần biết rằng bất kỳ triển khai nào được cung cấp sẽ thực hiện được.


Bây giờ, bạn có thể tự do sử dụng cái này hay cái khác.

 $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$

Giờ đây, bạn có thể linh hoạt thay đổi toàn bộ nhà cung cấp API và mã của bạn sẽ luôn hoạt động như cũ. Bạn không cần phải thay đổi bất cứ điều gì về nó vì bạn đã mã hóa thành một giao diện , vì vậy không có mối lo ngại nào mà chúng tôi nêu ra trước đó sẽ là vấn đề.

Luôn có tiền thưởng

Trong ví dụ của chúng tôi, bằng cách mã hóa một giao diện, chúng tôi cũng đã tôn trọng ba trong số các nguyên tắc RẮN mà không hề biết rằng chúng tôi đã làm như vậy, hãy để tôi giải thích thêm.


Tôi sẽ không đi vào chi tiết; mỗi nguyên tắc có thể có một bài viết dài. Đây chỉ là lời giải thích ngắn gọn để cho thấy những gì chúng tôi thu được khi mã hóa giao diện.

Nguyên tắc đóng mở

Nguyên tắc đầu tiên mà chúng tôi tôn trọng là Nguyên tắc Đóng-Mở, trong đó nêu rõ rằng mã phải được mở để mở rộng và đóng để sửa đổi. Nghe có vẻ khó khăn nhưng bạn đã đạt được nó. Hãy suy nghĩ về điều này, ChatBot hiện đã đóng cửa để sửa đổi; chúng tôi sẽ không chạm vào mã nữa. Đây là mục tiêu của chúng tôi ngay từ đầu.


Tuy nhiên, nó có thể được mở rộng; nếu chúng tôi thêm nhà cung cấp thứ 3, thứ 4 hoặc thậm chí thứ 5 thì không có gì có thể ngăn cản chúng tôi. Chúng tôi có thể triển khai giao diện và lớp của chúng tôi có thể sử dụng nó ngay lập tức mà không cần thay đổi.

Thay thế Liskov

Tôi sẽ không làm bạn nhàm chán với định nghĩa của nó, nhưng về cơ bản, nó nói rằng bạn có thể thay thế các lớp bằng TẤT CẢ các lớp con của chúng và ngược lại. Về mặt kỹ thuật, tất cả các nhà cung cấp AI của chúng tôi are-a AIProvider và việc triển khai của họ có thể được hoán đổi cho nhau mà không ảnh hưởng đến tính chính xác của ChatBot , sau này thậm chí còn không biết mình đang sử dụng nhà cung cấp nào 😂, vì vậy, chúng tôi tôn trọng cô Liskov .

Đảo ngược phụ thuộc

Tôi phải thừa nhận, cái này có thể có bài viết riêng của nó. Nhưng nói một cách đơn giản, nguyên tắc nói rằng bạn nên phụ thuộc vào sự trừu tượng hơn là cụ thể, đó chính xác là những gì chúng tôi đang làm. Chúng tôi phụ thuộc vào một nhà cung cấp chứ không phải một nhà cung cấp cụ thể như Open AI.


Hãy nhớ rằng, tất cả những điều này là do chúng ta đã mã hóa thành một giao diện.

Cuối cùng nó sẽ nhấp vào cho bạn

Bất cứ khi nào bạn cập nhật một lớp mà bạn biết là không nên cập nhật và mã của bạn đang bị tấn công bởi các câu lệnh if, bạn cần có một giao diện. Hãy luôn tự hỏi bản thân, lớp học này có thực sự cần biết cách thực hiện không? Tôi có sử dụng nhà cung cấp dịch vụ này mãi mãi không? Hoặc trình điều khiển cơ sở dữ liệu? Nếu không, bạn biết phải làm gì.


Như đã nói, chỉ cần cho nó một chút thời gian, cuối cùng nó sẽ phù hợp với bạn .