Tại sao (/ đã) Bertrand Meyer nghĩ rằng phân lớp là cách duy nhất để mở rộng mô-đun đóng kín của Cameron?


19

Trong Xây dựng phần mềm hướng đối tượng của Meyer (1988), ông định nghĩa nguyên tắc mở / đóng như sau:

  • Một mô-đun sẽ được cho là mở nếu nó vẫn có sẵn để mở rộng. Ví dụ, có thể thêm các trường vào cấu trúc dữ liệu mà nó chứa hoặc các phần tử mới vào tập hợp các hàm mà nó thực hiện.
  • Một mô-đun sẽ được cho là đóng nếu nó có sẵn để sử dụng bởi các mô-đun khác. Điều này giả định rằng mô-đun đã được cung cấp một mô tả ổn định, được xác định rõ (giao diện theo nghĩa ẩn thông tin).

Anh tiếp tục nói:

Nếu bạn mở lại một mô-đun, bạn cũng phải mở lại tất cả các máy khách của nó để cập nhật chúng, vì chúng dựa vào phiên bản cũ. Re [Vấn đề này] phát sinh mỗi khi một mô-đun phải được mở rộng bởi một chức năng hoặc thành phần dữ liệu mới, kích hoạt các thay đổi trong các máy khách trực tiếp và gián tiếp. ... Với các phương pháp cổ điển để thiết kế và lập trình, không có cách nào để viết các mô-đun cả mở và đóng.

Giải pháp của Meyer cho vấn đề nan giải này là: không bao giờ mở rộng mô-đun thư viện bằng cách sửa đổi các lớp hiện có; thay vào đó, hãy viết một mô-đun mới phân lớp các lớp hiện có và có các máy khách mới phụ thuộc vào mô-đun mới đó.

Bây giờ, vào năm 1988, tôi đã viết các chương trình đồ chơi (thủ tục) trong Turbo Pascal và Blankenship Basic, và kinh nghiệm chuyên môn trong thế kỷ 21 của tôi là về JVM, CLR và bằng các ngôn ngữ động, vì vậy tôi không biết Meyer có nghĩa là gì bởi "cách tiếp cận cổ điển để thiết kế và lập trình".

Một ví dụ cụ thể về lý do tại sao các mô-đun máy khách phải được mở lại (một câu lệnh chuyển đổi về một bảng liệt kê hiện có nhiều thành viên hơn, yêu cầu nhiều trường hợp hơn) có vẻ hợp lý, nhưng anh ta gần như không biện minh rằng mỗi khi bạn thêm chức năng vào thư viện mô-đun, bạn cần cập nhật tất cả các khách hàng của nó .

Có một lý do lịch sử mà khẳng định này dường như tự rõ ràng vào năm 1988? Có phải, việc thêm các hàm hoặc cấu trúc dữ liệu vào thư viện tĩnh C đã thay đổi bố cục sao cho ngay cả với các API tương thích ngược, các máy khách phải được biên dịch lại? Hay Meyer thực sự chỉ đang nói về một cơ chế để thực thi tính tương thích ngược API?


3
Câu hỏi thú vị! Tôi có cảm giác rằng câu trả lời sẽ liên quan đến sự khác biệt cơ bản giữa các kiểu dữ liệu trừu tượng và trừu tượng hóa dữ liệu hướng đối tượng , là hai cơ chế trừu tượng hóa dữ liệu thống trị trong Lập trình mô đun (mà Betrand Meyer đang gọi là "cách tiếp cận cổ điển" ") và Lập trình hướng đối tượng (đọc các bình luận!), tương ứng.
Jörg W Mittag

Điều đó lạ thật. Nó dường như mâu thuẫn với thực tế (ngay cả vào năm 1988). Ngoài ra, cách tiếp cận chủ trương của ông sẽ dẫn đến sự gia tăng các mô-đun không có ích.

@ dan1111: Cách tiếp cận kế thừa của Eiffel, bao gồm, nhưng không giới hạn ở cách tiếp cận đa thừa kế của nó khác với C ++, Java, C #, v.v., vì vậy không có gì đáng ngạc nhiên khi cách tiếp cận này khác. Rốt cuộc, ông đã phát triển Eiffel để hỗ trợ quan điểm của mình về OO.
Jörg W Mittag

Câu trả lời:


18

Theo như tôi có thể nói, câu hỏi này đã được trả lời bởi chính Bertrand Meyer và câu trả lời là, tuyên bố này không chính xác. Với các phương pháp cổ điển để thiết kế và lập trình, thực sự có thể có một cách để viết các mô-đun cả mở và đóng.

Để tìm ra điều này, bạn cần nghiên cứu phiên bản thứ hai của cuốn sách này (xuất bản chín năm sau, năm 1997). Theo Lời nói đầu cho phiên bản thứ hai , đó là

không phải là một bản cập nhật mà là kết quả của việc làm lại kỹ lưỡng. Không một đoạn nào của phiên bản gốc đã bị bỏ hoang. (Thực sự chỉ là một dòng duy nhất.)

Đặc biệt, tuyên bố khiến bạn bối rối đã ra đi. Vẫn còn có chương nguyên tắc đóng-mở trong "§3.3 Năm nguyên tắc", và có thảo luận kỹ hơn về chủ đề này trong "§14.7 Giới thiệu về quyền thừa kế" nhưng tuyên bố từ phiên bản đầu tiên không còn nữa.

Những gì ở đó thay vào đó tập trung vào cách nó thuận tiện và thành ngữ hơn trong cách tiếp cận OO trái ngược với những cách trước đây,

Nhờ kế thừa, các nhà phát triển OO có thể áp dụng cách tiếp cận gia tăng hơn nhiều cho phát triển phần mềm so với trước đây là có thể với các phương pháp trước đó ... (§3.3)

Yêu cầu kép này (mở và đóng) trông giống như một vấn đề nan giải và các cấu trúc mô-đun cổ điển không cung cấp manh mối. Nhưng thừa kế giải quyết nó. Một lớp được đóng lại, vì nó có thể được biên dịch, lưu trữ trong thư viện, theo đường cơ sở và được sử dụng bởi các lớp máy khách. Nhưng nó cũng mở, vì bất kỳ lớp mới nào cũng có thể sử dụng nó làm cha mẹ, thêm các tính năng mới và khai báo lại các tính năng được kế thừa; trong quá trình này, không cần thay đổi bản gốc hoặc làm phiền khách hàng của nó ... (§14.7)

Vì bạn dường như cũng tự hỏi về "phương pháp cổ điển" Meyer có ý nghĩa gì ở đây, bạn có thể tìm thấy lời giải thích về những điều này trong §4.7 Cấu trúc mô đun truyền thống . Phần này giải thích rằng đó là "thư viện thói quen" và "gói" (đối với phần sau, tác giả cho biết thuật ngữ này được lấy từ Ada và đề cập đến các ngôn ngữ khác có tính năng này - cụm trong CLU và mô-đun trong Modula).

Nếu bạn nghĩ về nó, không có cách tiếp cận nào trong số này ban đầu được dự định để hỗ trợ viết mã tuân thủ nguyên tắc đóng mở. Điều này có thể dẫn tác giả đến đánh giá hơi sớm của họ mà sau đó đã được sửa trong phiên bản thứ hai.


Đối với những gì cụ thể khiến tác giả thay đổi suy nghĩ về tuyên bố đó ở giữa phiên bản thứ nhất và thứ hai, tôi nghĩ người ta có thể tìm thấy câu trả lời, một lần nữa, trong chính cuốn sách, cụ thể là trong Phần F: Áp dụng phương pháp này trong nhiều ngôn ngữ và môi trường khác nhau " . chương này, tác giả thảo luận về cách các phương thức hướng đối tượng có thể được sử dụng trong các ngôn ngữ cũ:

Các ngôn ngữ cổ điển như Fortran hoàn toàn không phải là OO, nhưng những người vẫn phải sử dụng chúng ... có thể muốn áp dụng càng nhiều ý tưởng OO càng khả thi trong giới hạn của các phương pháp cũ này.

Cụ thể, trong phần này Meyer giải thích chi tiết về cách có thể thực hiện kế thừa (với một số hạn chế và hạn chế, nhưng vẫn) trong C và thậm chí ở Fortran.

Bạn thấy đấy, điều này thực sự kêu gọi sửa đổi tuyên bố đó từ phiên bản đầu tiên. Thực tế dường như không thể giải thích làm thế nào để hòa giải "với các phương pháp cổ điển ... không có cách nào" với các ví dụ thực tế về cách chính xác nó có thể được thực hiện.


Thú vị, và tôi chắc chắn sẽ phải cố gắng để có được phiên bản thứ hai, nhưng tôi vẫn không rõ tại sao ngay cả một thư viện "cổ điển" không OO cũng không thể thêm (ít nhất là một số loại) tính năng mà không làm phiền khách hàng
David Moles

Điều @DavidMoles là, nó có thể , và phần cuối câu trả lời của tôi giải thích điều đó, và chính Meyer đã nhận ra rằng (khi anh ấy làm lại cho Phiên bản 2) và thậm chí đã đưa ra ví dụ về cách nó có thể được thực hiện. "Đối với những gì cụ thể đã khiến tác giả thay đổi suy nghĩ của họ ..." vv
gnat

Hừm. Tôi không thấy "phiên bản 2 của thư viện này, thay thế phiên bản 1 và tương thích ngược với nó, thêm các chức năng sau đây" như "thừa kế" ngoại trừ theo cách khái niệm rộng nhất có thể.
David Moles

(Kế thừa, với tôi, ngụ ý rằng phiên bản 1 vẫn còn và được gọi bởi phiên bản 2.)
David Moles

@DavidMoles thay thế bằng phiên bản 2 (như thay đổi mã nguồn và biên dịch lại ) sẽ không đủ điều kiện là "đóng để sửa đổi", bạn chỉ cần kiểm tra điều này trong bài viết Wikipedia : "thực thể có thể cho phép hành vi của nó được mở rộng mà không cần sửa đổi mã nguồn của nó ... "
gnat
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.