Tại sao một lập trình viên muốn tách biệt thực hiện khỏi giao diện?


18

Mẫu thiết kế cầu tách biệt việc thực hiện với giao diện của một chương trình.

Tại sao điều này là lợi thế?


Để ngăn chặn sự trừu tượng bị rò rỉ
SK-logic

1
Điều này dường như đã được mọi người hiểu, nhưng đối với những người xem mới, Bridge Design không phải là về triển khai và giao diện "của một chương trình" mà là các phần, thậm chí có thể là các phần nhỏ của chương trình. Toàn bộ chương trình sẽ là một tập hợp các giao diện và triển khai (với mỗi giao diện có một hoặc nhiều triển khai). Câu đầu tiên có lẽ nên là: "Mẫu thiết kế cầu tách biệt các giao diện với các triển khai của chúng trong tất cả mã nguồn của bạn."
RalphChapin

Câu trả lời:


35

Nó cho phép bạn thay đổi việc thực hiện độc lập với giao diện. Điều này giúp đối phó với các yêu cầu thay đổi.

Ví dụ kinh điển là thay thế việc thực hiện lưu trữ trong một giao diện bằng một cái gì đó lớn hơn, tốt hơn, nhanh hơn, nhỏ hơn hoặc khác đi mà không phải thay đổi phần còn lại của hệ thống.


23

Ngoài câu trả lời của Daniel, tách giao diện khỏi triển khai thông qua các khái niệm như đa hình cho phép bạn tạo một số triển khai của cùng một giao diện thực hiện những điều tương tự theo các cách khác nhau.

Ví dụ: rất nhiều ngôn ngữ có khái niệm về một luồng ở đâu đó trong thư viện chuẩn. Luồng là thứ chứa dữ liệu để truy cập nối tiếp. Nó có hai thao tác cơ bản: Đọc (tải số byte X tiếp theo từ luồng) và Ghi (thêm số byte dữ liệu X vào luồng) và đôi khi là thứ ba, Tìm kiếm (đặt lại "vị trí hiện tại" của luồng đến một địa điểm mới).

Đó là một khái niệm đủ đơn giản, nhưng hãy nghĩ về tất cả những điều bạn có thể làm với nó. Rõ ràng nhất là tương tác với các tập tin trên đĩa. Một luồng tệp sẽ cho phép bạn đọc dữ liệu từ một tệp hoặc ghi vào nó. Nhưng nếu bạn muốn gửi dữ liệu qua kết nối mạng thì sao?

Nếu bạn dựa trực tiếp vào việc triển khai, bạn sẽ phải viết ra hai thói quen hoàn toàn khác nhau để lưu cùng một dữ liệu vào một tệp hoặc gửi nó qua mạng. Nhưng nếu bạn có giao diện truyền phát, bạn có thể tạo hai triển khai khác nhau của nó ( FileStreamNetworkStream) gói gọn các chi tiết cụ thể của việc gửi dữ liệu cần đến, và sau đó bạn chỉ cần viết mã liên quan đến việc lưu tệp một lần . Đột nhiên SaveToFile, SendOverNetworkthói quen của bạn đơn giản hơn rất nhiều: họ chỉ cần thiết lập một luồng loại thích hợp và chuyển nó sang SaveDatathói quen, chấp nhận giao diện luồng - không cần quan tâm loại nào, miễn là nó có thể thực hiện Viết thao tác - và lưu dữ liệu vào luồng.

Điều đó cũng có nghĩa là nếu định dạng dữ liệu của bạn thay đổi, bạn không phải thay đổi nó ở nhiều nơi khác nhau. Nếu bạn tập trung mã tiết kiệm dữ liệu của mình theo một thói quen có luồng, thì đó là nơi duy nhất cần cập nhật, do đó bạn không thể vô tình đưa ra lỗi bằng cách chỉ thay đổi một nơi khi bạn cần thay đổi cả hai. Vì vậy, việc tách các giao diện khỏi việc triển khai và sử dụng đa hình làm cho mã trở nên đơn giản hơn để đọc và hiểu và điều đó ít có khả năng có lỗi hơn.


1
Đây là một trong những tính năng mạnh nhất của OOP. Tôi chỉ thích nó ...
Radu Murzea

1
Làm thế nào là hình thức khác nhau bằng cách sử dụng giao diện đơn giản?
vainolo

@Vainolo: Nó giúp sử dụng lại mã. Ngay cả khi bạn có nhiều loại luồng, tất cả chúng sẽ thực hiện rất nhiều thứ giống nhau. Nếu bạn bắt đầu với IStreamGiao diện, bạn phải phát minh lại toàn bộ bộ chức năng cho mỗi luồng. Nhưng nếu bạn bắt đầu với một lớp luồng trừu tượng cơ sở, nó có thể chứa tất cả trạng thái và chức năng chung, sau đó để con cháu thực hiện các tính năng riêng biệt.
Mason Wheeler

2
@RaduMurzea điều này không dành riêng cho OOP. Các lớp loại cho phép bạn làm điều tương tự theo kiểu hoàn toàn không OOP.
Wes

@ Chính xác, chỉ muốn nói như vậy, và sau đó tôi đọc bình luận của bạn.
jhegedus

4

Bạn thực sự có hai câu hỏi rất khác nhau ở đây, mặc dù chúng có liên quan.

Câu hỏi chung hơn là câu hỏi trong tiêu đề, tại sao bạn lại tách giao diện khỏi việc thực hiện nói chung. Câu hỏi thứ hai là tại sao mô hình cầu là hữu ích. Chúng có liên quan vì mẫu cầu là một cách cụ thể để tách giao diện khỏi triển khai, điều này cũng có một số hậu quả cụ thể khác.

Câu hỏi chung là một cái gì đó quan trọng cho mọi lập trình viên để hiểu. Đó là những gì ngăn cản những thay đổi trong một chương trình lan truyền khắp nơi. Tôi không thể tưởng tượng con người có thể lập trình mà không sử dụng cái này.

Khi bạn viết một câu lệnh bổ sung đơn giản bằng ngôn ngữ lập trình, đó đã là một sự trừu tượng hóa, (ngay cả khi nó không sử dụng quá tải toán tử để thêm ma trận hoặc một cái gì đó tương tự) đi qua khá nhiều mã khác trước khi cuối cùng nó được thực thi trên một mạch trong máy tính của bạn. Nếu không có sự phân tách giao diện (giả sử "3 + 5"), từ việc triển khai (một loạt mã máy), thì bạn sẽ phải thay đổi mã của mình mỗi khi triển khai thay đổi (như bạn muốn chạy trên một bộ xử lý mới).

Ngay cả trong một ứng dụng CRUD đơn giản, mọi chữ ký phương thức, theo nghĩa rộng, là giao diện để thực hiện.

Tất cả các loại trừu tượng này đều có cùng một mục tiêu cơ bản - có mã gọi thể hiện ý định của nó theo cách trừu tượng nhất có thể cung cấp cho người thực hiện nhiều thông tin cần thiết. Điều đó cung cấp sự ghép đôi tối thiểu có thể giữa chúng và hạn chế hiệu ứng gợn khi mã cần được thay đổi càng nhiều càng tốt.

Nghe có vẻ đơn giản, nhưng trong thực tế, nó trở nên phức tạp.

Mẫu cầu là một cách cụ thể để tách các bit thực hiện nhất định thành các giao diện. Sơ đồ lớp của mẫu có nhiều thông tin hơn mô tả. Nó giống như một cách để có các mô-đun có thể cắm hơn là một cây cầu, nhưng họ đặt tên cho nó là cầu nối vì nó thường được sử dụng trong đó các mô-đun đã được tạo trước giao diện. Vì vậy, việc tạo một giao diện chung cho các triển khai hiện có tương tự sắp xếp "cầu nối" sự khác biệt và cho phép bạn viết mã để làm việc với bất kỳ triển khai nào.

Vì vậy, giả sử bạn muốn viết một phần bổ trợ cho trình xử lý văn bản, nhưng bạn muốn nó hoạt động trên nhiều trình xử lý văn bản. Bạn có thể tạo một giao diện trừu tượng hóa chức năng dựa trên trình xử lý văn bản mà bạn cần (và phải được triển khai bởi mỗi trình xử lý văn bản vì bạn không thể thay đổi giao diện đó) và một người triển khai giao diện đó cho mỗi trình xử lý văn bản bạn muốn hỗ trợ. Sau đó, ứng dụng của bạn có thể gọi giao diện đó và không phải lo lắng về các chi tiết của từng trình xử lý.

Nó thực sự chi tiết hơn một chút, bởi vì mỗi lớp thực sự có thể là một hệ thống phân cấp lớp (vì vậy, có thể không chỉ có một trình xử lý văn bản trừu tượng, mà còn là một Tài liệu trừu tượng, TextSelection, v.v., với các triển khai cụ thể cho từng lớp), nhưng nó cùng một ý tưởng.

Nó hơi giống mặt tiền, ngoại trừ trong trường hợp này, lớp trừu tượng được tập trung vào việc cung cấp cùng một giao diện cho nhiều hệ thống cơ bản.

Nó liên quan đến Inversion Of Control, vì trình triển khai cụ thể sẽ được chuyển đến các phương thức hoặc hàm tạo và sẽ xác định việc thực hiện thực tế được gọi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.