Mối quan hệ giữa một lớp và một đối tượng python là gì?
Trong bài viết này, bạn sẽ khám phá tính kế thừa và thành phần trong Python. Kế thừa và thành phần là hai khái niệm quan trọng trong lập trình hướng đối tượng, mô hình hóa mối quan hệ giữa hai lớp. Chúng là các khối xây dựng của thiết kế hướng đối tượng và chúng giúp các lập trình viên viết mã có thể tái sử dụng Show
Đến cuối bài viết này, bạn sẽ biết cách
Tiền thưởng miễn phí. Nhấp vào đây để có quyền truy cập vào Bảng cheat Python OOP miễn phí chỉ cho bạn các hướng dẫn, video và sách hay nhất để tìm hiểu thêm về Lập trình hướng đối tượng với Python Kế thừa và Thành phần là gì?Kế thừa và thành phần là hai khái niệm chính trong lập trình hướng đối tượng, mô hình hóa mối quan hệ giữa hai lớp. Họ thúc đẩy thiết kế của một ứng dụng và xác định cách ứng dụng sẽ phát triển khi các tính năng mới được thêm vào hoặc các yêu cầu thay đổi Cả hai đều cho phép tái sử dụng mã, nhưng chúng thực hiện theo những cách khác nhau Loại bỏ các quảng cáoKế thừa là gì?Các mô hình thừa kế cái được gọi là một mối quan hệ. Điều này có nghĩa là khi bạn có một lớp 6 kế thừa từ một lớp 7, bạn đã tạo một mối quan hệ trong đó 6 là một phiên bản chuyên biệt của 7Tính kế thừa được biểu diễn bằng Ngôn ngữ mô hình hóa thống nhất hoặc UML theo cách sau Các lớp được biểu diễn dưới dạng các hộp có tên lớp ở trên cùng. Mối quan hệ thừa kế được biểu diễn bằng mũi tên từ lớp dẫn xuất trỏ đến lớp cơ sở. Từ kéo dài thường được thêm vào mũi tên Ghi chú. Trong quan hệ thừa kế
Giả sử bạn có một lớp cơ sở 0 và bạn lấy từ nó để tạo một lớp 1. Mối quan hệ thừa kế nói rằng một 1 là một 0. Điều này có nghĩa là 1 kế thừa giao diện và triển khai của 0 và các đối tượng 1 có thể được sử dụng để thay thế các đối tượng 0 trong ứng dụngĐiều này được gọi là nguyên tắc thay thế Liskov. Nguyên tắc nói rằng “trong một chương trình máy tính, nếu 8 là một kiểu con của 9, thì các đối tượng kiểu 9 có thể được thay thế bằng các đối tượng kiểu 8 mà không làm thay đổi bất kỳ thuộc tính mong muốn nào của chương trình”Trong bài viết này, bạn sẽ thấy lý do tại sao bạn phải luôn tuân theo nguyên tắc thay thế Liskov khi tạo hệ thống phân cấp lớp của mình và những vấn đề bạn sẽ gặp phải nếu không tuân theo Thành phần là gì?Thành phần là một khái niệm mà các mô hình có một mối quan hệ. Nó cho phép tạo các kiểu phức tạp bằng cách kết hợp các đối tượng thuộc các kiểu khác. Điều này có nghĩa là một lớp 602 có thể chứa một đối tượng của một lớp khác 603. Mối quan hệ này có nghĩa là một 602 có một 603UML đại diện cho thành phần như sau Thành phần được thể hiện thông qua một đường có hình thoi tại lớp tổng hợp trỏ đến lớp thành phần. Mặt tổng hợp có thể thể hiện bản chất của mối quan hệ. Số lượng cho biết số lượng hoặc phạm vi hợp lệ của các thể hiện 603 mà lớp 602 sẽ chứaTrong sơ đồ trên, 608 biểu thị rằng lớp 602 chứa một đối tượng kiểu 603. Cardinality có thể được thể hiện theo những cách sau
Ghi chú. Các lớp chứa các đối tượng của các lớp khác thường được gọi là tổng hợp, trong đó các lớp được sử dụng để tạo các loại phức tạp hơn được gọi là các thành phần Ví dụ: lớp 1 của bạn có thể được tạo bởi một đối tượng khác thuộc loại 618. Bố cục cho phép bạn thể hiện mối quan hệ đó bằng cách nói một 1 có một 618Thành phần cho phép bạn sử dụng lại mã bằng cách thêm các đối tượng vào các đối tượng khác, thay vì kế thừa giao diện và triển khai của các lớp khác. Cả hai lớp 1 và 622 đều có thể tận dụng chức năng của 618 thông qua thành phần mà không cần lấy lớp này từ lớp kiaTổng quan về tính kế thừa trong PythonMọi thứ trong Python đều là đối tượng. Mô-đun là đối tượng, định nghĩa lớp và hàm là đối tượng, và tất nhiên, đối tượng được tạo từ lớp cũng là đối tượng Kế thừa là một tính năng bắt buộc của mọi ngôn ngữ lập trình hướng đối tượng. Điều này có nghĩa là Python hỗ trợ tính kế thừa và như bạn sẽ thấy ở phần sau, đây là một trong số ít ngôn ngữ hỗ trợ tính đa kế thừa Khi bạn viết mã Python bằng các lớp, bạn đang sử dụng tính kế thừa ngay cả khi bạn không biết mình đang sử dụng nó. Hãy xem điều đó có nghĩa là gì Loại bỏ các quảng cáoSiêu lớp đối tượngCách dễ nhất để xem tính kế thừa trong Python là nhảy vào trình bao tương tác Python và viết một chút mã. Bạn sẽ bắt đầu bằng cách viết lớp đơn giản nhất có thể >>> 8Bạn đã khai báo một lớp 624 không làm được gì nhiều, nhưng nó sẽ minh họa các khái niệm kế thừa cơ bản nhất. Bây giờ bạn đã khai báo lớp, bạn có thể sử dụng hàm 625 để liệt kê các thành viên của nó>>> 6 625 trả về danh sách tất cả các thành viên trong đối tượng được chỉ định. Bạn chưa khai báo bất kỳ thành viên nào trong 624, vậy danh sách này đến từ đâu? >>> 4Như bạn có thể thấy, hai danh sách gần như giống hệt nhau. Có một số thành viên bổ sung trong 624 như 629 và 630, nhưng mọi thành viên của lớp 631 cũng có mặt trong 624Điều này là do mọi lớp bạn tạo trong Python đều bắt nguồn từ 631. Bạn có thể rõ ràng hơn và viết 634, nhưng nó thừa và không cần thiếtGhi chú. Trong Python 2, bạn phải bắt nguồn rõ ràng từ 631 vì những lý do nằm ngoài phạm vi của bài viết này, nhưng bạn có thể đọc về nó trong phần Kiểu mới và lớp cổ điển của tài liệu Python 2Ngoại lệ là một ngoại lệMọi lớp mà bạn tạo bằng Python sẽ ngầm định xuất phát từ 631. Ngoại lệ đối với quy tắc này là các lớp được sử dụng để chỉ ra lỗi bằng cách đưa ra một ngoại lệBạn có thể thấy sự cố khi sử dụng trình thông dịch tương tác Python >>> 4Bạn đã tạo một lớp mới để chỉ ra một loại lỗi. Sau đó, bạn đã cố gắng sử dụng nó để đưa ra một ngoại lệ. Một ngoại lệ được đưa ra nhưng đầu ra cho biết rằng ngoại lệ đó thuộc loại 637 không phải 638 và tất cả 639 640 là lớp cơ sở được cung cấp cho tất cả các loại lỗi. Để tạo một loại lỗi mới, bạn phải dẫn xuất lớp của mình từ 640 hoặc một trong các lớp dẫn xuất của nó. Quy ước trong Python là lấy các loại lỗi tùy chỉnh của bạn từ 642, từ đó bắt nguồn từ 640Cách chính xác để xác định loại lỗi của bạn là như sau >>> 2Như bạn có thể thấy, khi bạn tăng 638, đầu ra cho biết chính xác loại lỗi được đưa raTạo phân cấp lớpKế thừa là cơ chế bạn sẽ sử dụng để tạo phân cấp của các lớp liên quan. Các lớp liên quan này sẽ chia sẻ một giao diện chung sẽ được định nghĩa trong các lớp cơ sở. Các lớp dẫn xuất có thể chuyên biệt hóa giao diện bằng cách cung cấp một triển khai cụ thể khi áp dụng Trong phần này, bạn sẽ bắt đầu lập mô hình hệ thống nhân sự. Ví dụ này sẽ chứng minh việc sử dụng tính kế thừa và cách các lớp dẫn xuất có thể cung cấp triển khai cụ thể của giao diện lớp cơ sở Hệ thống nhân sự cần xử lý bảng lương cho nhân viên của công ty, nhưng có nhiều loại nhân viên khác nhau tùy thuộc vào cách tính lương của họ Bạn bắt đầu bằng cách triển khai lớp 645 xử lý bảng lương 5 645 triển khai phương pháp 647 lấy một tập hợp nhân viên và in 648, 649 của họ và kiểm tra số lượng bằng phương pháp 647 hiển thị trên từng đối tượng nhân viênBây giờ, bạn triển khai lớp cơ sở 651 xử lý giao diện chung cho mọi loại nhân viên 2 651 là lớp cơ sở cho tất cả các loại nhân viên. Nó được xây dựng với một 648 và một 649. Những gì bạn đang nói là mỗi 651 phải được gán một 648 cũng như một tênHệ thống nhân sự yêu cầu mỗi 651 được xử lý phải cung cấp giao diện 647 trả về tiền lương hàng tuần cho nhân viên. Việc triển khai giao diện đó khác nhau tùy thuộc vào loại 651Ví dụ, nhân viên hành chính có mức lương cố định, vì vậy hàng tuần họ được trả số tiền như nhau 1Bạn tạo một lớp dẫn xuất 660 kế thừa 651. Lớp được khởi tạo với 648 và 649 theo yêu cầu của lớp cơ sở và bạn sử dụng 664 để khởi tạo các thành viên của lớp cơ sở. Bạn có thể đọc tất cả về 664 trong Supercharge Your Classes With Python super() 660 cũng yêu cầu tham số khởi tạo 667 đại diện cho số tiền mà nhân viên kiếm được mỗi tuầnLớp cung cấp phương thức 647 bắt buộc được sử dụng bởi hệ thống nhân sự. Việc triển khai chỉ trả về số tiền được lưu trữ trong 667Công ty cũng sử dụng công nhân sản xuất được trả lương theo giờ, vì vậy bạn thêm một số 1670 vào hệ thống nhân sự
Lớp 670 được khởi tạo với 648 và 649, giống như lớp cơ sở, cộng với 674 và 675 cần thiết để tính bảng lương. Phương thức 647 được triển khai bằng cách trả về số giờ đã làm việc nhân với tỷ lệ giờCuối cùng, công ty tuyển dụng các cộng tác viên bán hàng được trả lương cố định cộng với hoa hồng dựa trên doanh số bán hàng của họ, vì vậy bạn tạo một lớp 677
Bạn lấy được 677 từ 660 vì cả hai lớp đều có một 667 để xem xét. Đồng thời, 677 được khởi tạo với giá trị 682 dựa trên doanh số bán hàng cho nhân viên 647 tận dụng việc triển khai lớp cơ sở để truy xuất mức lương của 684 và thêm giá trị hoa hồngVì 677 bắt nguồn từ 660, nên bạn có quyền truy cập trực tiếp vào thuộc tính 667 và bạn có thể triển khai 647 bằng cách sử dụng giá trị của thuộc tính đóVấn đề với việc truy cập thuộc tính trực tiếp là nếu việc triển khai 689 thay đổi, thì bạn cũng sẽ phải thay đổi việc triển khai 690. Tốt hơn là nên dựa vào phương thức đã được triển khai trong lớp cơ sở và mở rộng chức năng khi cầnBạn đã tạo hệ thống phân cấp lớp đầu tiên của mình cho hệ thống. Sơ đồ UML của các lớp trông như thế này Sơ đồ cho thấy hệ thống phân cấp thừa kế của các lớp. Các lớp dẫn xuất triển khai giao diện 691, được yêu cầu bởi 645. Việc triển khai 693 yêu cầu các đối tượng 694 được thông qua có chứa một triển khai 648, 649 và 697Các giao diện được biểu diễn tương tự như các lớp với từ giao diện phía trên tên giao diện. Tên giao diện thường được bắt đầu bằng chữ hoa 698Ứng dụng tạo nhân viên của mình và chuyển họ đến hệ thống tính lương để xử lý bảng lương 60Bạn có thể chạy chương trình trong dòng lệnh và xem kết quả 61Chương trình tạo ba đối tượng nhân viên, một đối tượng cho mỗi lớp dẫn xuất. Sau đó, nó tạo hệ thống tính lương và chuyển danh sách nhân viên sang phương thức 647 của nó, tính toán bảng lương cho từng nhân viên và in kết quảLưu ý cách lớp cơ sở 651 không định nghĩa phương thức 647. Điều này có nghĩa là nếu bạn định tạo một đối tượng 651 đơn giản và chuyển nó tới đối tượng 645, thì bạn sẽ gặp lỗi. Bạn có thể dùng thử trong trình thông dịch tương tác Python>>> 62Mặc dù bạn có thể khởi tạo một đối tượng 651 nhưng đối tượng đó không thể được sử dụng bởi 645. Tại sao? . Để đáp ứng các yêu cầu của 645, bạn sẽ muốn chuyển đổi lớp 651, hiện là lớp cụ thể, thành lớp trừu tượng. Bằng cách đó, không có nhân viên nào chỉ là một 651, mà là một nhân viên thực hiện 647Loại bỏ các quảng cáoCác lớp cơ sở trừu tượng trong PythonLớp 651 trong ví dụ trên được gọi là lớp cơ sở trừu tượng. Các lớp cơ sở trừu tượng tồn tại để được kế thừa, nhưng không bao giờ được khởi tạo. Python cung cấp mô-đun 413 để định nghĩa các lớp cơ sở trừu tượngBạn có thể sử dụng dấu gạch dưới hàng đầu trong tên lớp của mình để thông báo rằng các đối tượng của lớp đó không nên được tạo. Dấu gạch dưới cung cấp một cách thân thiện để ngăn việc sử dụng sai mã của bạn, nhưng chúng không ngăn người dùng háo hức tạo các phiên bản của lớp đó Mô-đun 413 trong thư viện chuẩn Python cung cấp chức năng ngăn việc tạo các đối tượng từ các lớp cơ sở trừu tượngBạn có thể sửa đổi việc triển khai lớp 651 để đảm bảo rằng nó không thể được khởi tạo 63Bạn lấy được 651 từ 417, biến nó thành một lớp cơ sở trừu tượng. Sau đó, bạn trang trí phương thức 647 với trình trang trí 419Thay đổi này có hai tác dụng phụ tốt đẹp
Bạn có thể thấy rằng các đối tượng kiểu 651 không thể được tạo bằng trình thông dịch tương tác>>> 64Đầu ra cho thấy rằng lớp không thể được khởi tạo vì nó chứa một phương thức trừu tượng 697. Các lớp dẫn xuất phải ghi đè phương thức để cho phép tạo các đối tượng thuộc loại của chúngKế thừa triển khai so với Kế thừa giao diệnKhi bạn dẫn xuất một lớp này từ một lớp khác, lớp dẫn xuất sẽ kế thừa cả hai
Hầu hết thời gian, bạn sẽ muốn kế thừa việc triển khai một lớp, nhưng bạn sẽ muốn triển khai nhiều giao diện, để các đối tượng của bạn có thể được sử dụng trong các tình huống khác nhau Các ngôn ngữ lập trình hiện đại được thiết kế dựa trên khái niệm cơ bản này. Chúng cho phép bạn kế thừa từ một lớp duy nhất, nhưng bạn có thể triển khai nhiều giao diện Trong Python, bạn không cần phải khai báo giao diện một cách rõ ràng. Bất kỳ đối tượng nào triển khai giao diện mong muốn đều có thể được sử dụng thay cho đối tượng khác. Điều này được gọi là gõ vịt. Gõ vịt thường được giải thích là “nếu nó hoạt động giống như một con vịt, thì đó là một con vịt. ” Để minh họa điều này, bây giờ bạn sẽ thêm một lớp 426 vào ví dụ trên mà không bắt nguồn từ 651 65Lớp 426 không xuất phát từ lớp 651, nhưng nó hiển thị cùng một giao diện được yêu cầu bởi lớp 645. 693 yêu cầu một danh sách các đối tượng triển khai giao diện sau
Tất cả các yêu cầu này đều được đáp ứng bởi lớp 426, vì vậy 645 vẫn có thể tính toán biên chế của mìnhBạn có thể sửa đổi chương trình để sử dụng lớp 426 66Chương trình tạo một đối tượng 426 và thêm nó vào danh sách được xử lý bởi 645. Bây giờ bạn có thể chạy chương trình và xem đầu ra của nó 67Như bạn thấy, 645 vẫn có thể xử lý đối tượng mới vì nó đáp ứng giao diện mong muốnVì bạn không cần phải xuất phát từ một lớp cụ thể để chương trình có thể sử dụng lại các đối tượng của bạn, bạn có thể hỏi tại sao bạn nên sử dụng tính kế thừa thay vì chỉ triển khai giao diện mong muốn. Các quy tắc sau đây có thể giúp bạn
Bây giờ bạn có thể làm sạch ví dụ trên để chuyển sang chủ đề tiếp theo. Bạn có thể xóa tệp 446 rồi sửa đổi mô-đun 421 về trạng thái ban đầu 68Bạn đã loại bỏ việc nhập mô-đun 413 vì lớp 651 không cần phải trừu tượng. Bạn cũng đã xóa phương thức trừu tượng 697 khỏi phương thức này vì nó không cung cấp bất kỳ triển khai nàoVề cơ bản, bạn đang kế thừa việc triển khai các thuộc tính 648 và 649 của lớp 651 trong các lớp dẫn xuất của bạn. Vì 647 chỉ là một giao diện của phương thức 693, nên bạn không cần triển khai nó trong lớp cơ sở 651Lưu ý cách lớp 677 bắt nguồn từ lớp 660. Điều này có nghĩa là 677 kế thừa triển khai và giao diện của 660. Bạn có thể thấy cách phương thức 690 tận dụng việc triển khai lớp cơ sở vì nó dựa vào kết quả từ 462 để triển khai phiên bản của chính nóLoại bỏ các quảng cáoSự cố bùng nổ lớp họcNếu bạn không cẩn thận, tính kế thừa có thể dẫn bạn đến một cấu trúc phân cấp khổng lồ của các lớp khó hiểu và khó duy trì. Đây được gọi là vấn đề bùng nổ lớp Bạn đã bắt đầu xây dựng hệ thống phân cấp lớp gồm các loại 651 được sử dụng bởi 645 để tính bảng lương. Bây giờ, bạn cần thêm một số chức năng cho các lớp đó để chúng có thể được sử dụng với 465 mới 465 theo dõi năng suất dựa trên vai trò của nhân viên. Có nhiều vai trò nhân viên khác nhau
Với những yêu cầu đó, bạn bắt đầu thấy rằng 651 và các lớp dẫn xuất của nó có thể thuộc về một nơi nào đó khác với mô-đun 421 bởi vì bây giờ chúng cũng được sử dụng bởi 465Bạn tạo một mô-đun 470 và di chuyển các lớp đến đó 69Việc triển khai vẫn giữ nguyên, nhưng bạn chuyển các lớp sang mô-đun 694. Bây giờ, bạn thay đổi chương trình của mình để hỗ trợ thay đổi 40Bạn chạy chương trình và xác minh rằng nó vẫn hoạt động 61Với mọi thứ đã sẵn sàng, bạn bắt đầu thêm các lớp mới 42Đầu tiên, bạn thêm một lớp 472 bắt nguồn từ 660. Lớp hiển thị một phương thức 474 sẽ được sử dụng bởi hệ thống năng suất. Phương pháp lấy 475 nhân viên đã làm việcSau đó, bạn thêm 476, 477 và 478 rồi triển khai giao diện 474 để hệ thống năng suất có thể sử dụng chúngBây giờ, bạn có thể thêm lớp 480 43Lớp theo dõi nhân viên theo phương thức 481 lấy danh sách nhân viên và số giờ cần theo dõi. Bây giờ bạn có thể thêm hệ thống năng suất vào chương trình của mình 44Chương trình tạo danh sách nhân viên các loại. Danh sách nhân viên được gửi đến hệ thống năng suất để theo dõi công việc của họ trong 40 giờ. Sau đó, cùng một danh sách nhân viên được gửi đến hệ thống bảng lương để tính lương cho họ Bạn có thể chạy chương trình để xem đầu ra 45Chương trình hiển thị các nhân viên làm việc trong 40 giờ thông qua hệ thống năng suất. Sau đó, nó tính toán và hiển thị bảng lương cho từng nhân viên Chương trình hoạt động như mong đợi, nhưng bạn phải thêm bốn lớp mới để hỗ trợ các thay đổi. Khi có các yêu cầu mới, hệ thống phân cấp lớp của bạn chắc chắn sẽ phát triển, dẫn đến vấn đề bùng nổ lớp trong đó hệ thống phân cấp của bạn sẽ trở nên lớn đến mức chúng sẽ khó hiểu và khó duy trì Sơ đồ sau đây cho thấy hệ thống phân cấp lớp mới Sơ đồ cho thấy hệ thống phân cấp lớp đang phát triển như thế nào. Các yêu cầu bổ sung có thể có tác động theo cấp số nhân về số lượng lớp học với thiết kế này Loại bỏ các quảng cáoKế thừa nhiều lớpPython là một trong số ít ngôn ngữ lập trình hiện đại hỗ trợ đa kế thừa. Đa kế thừa là khả năng dẫn xuất một lớp từ nhiều lớp cơ sở cùng một lúc Đa kế thừa có tiếng xấu đến mức hầu hết các ngôn ngữ lập trình hiện đại không hỗ trợ nó. Thay vào đó, các ngôn ngữ lập trình hiện đại hỗ trợ khái niệm giao diện. Trong các ngôn ngữ đó, bạn kế thừa từ một lớp cơ sở duy nhất và sau đó triển khai nhiều giao diện, vì vậy lớp của bạn có thể được sử dụng lại trong các tình huống khác nhau Cách tiếp cận này đặt ra một số ràng buộc trong thiết kế của bạn. Bạn chỉ có thể kế thừa việc triển khai một lớp bằng cách xuất phát trực tiếp từ nó. Bạn có thể triển khai nhiều giao diện, nhưng bạn không thể kế thừa việc triển khai nhiều lớp Ràng buộc này tốt cho thiết kế phần mềm vì nó buộc bạn phải thiết kế các lớp của mình với ít phụ thuộc lẫn nhau hơn. Ở phần sau của bài viết này, bạn sẽ thấy rằng bạn có thể tận dụng nhiều triển khai thông qua thành phần, giúp phần mềm trở nên linh hoạt hơn. Tuy nhiên, phần này nói về đa thừa kế, vì vậy chúng ta hãy xem nó hoạt động như thế nào It turns out that sometimes temporary secretaries are hired when there is too much paperwork to do. Lớp 482 thực hiện vai trò của lớp 476 trong ngữ cảnh của lớp 465, nhưng đối với mục đích tính lương, nó là lớp 670Bạn nhìn vào thiết kế lớp học của bạn. It has grown a little bit, but you can still understand how it works. Có vẻ như bạn có hai lựa chọn
Sau đó, bạn nhớ rằng Python hỗ trợ đa kế thừa, vì vậy bạn quyết định xuất phát từ cả 476 và 670 46Python cho phép bạn kế thừa từ hai lớp khác nhau bằng cách chỉ định chúng giữa dấu ngoặc đơn trong khai báo lớp Bây giờ, bạn sửa đổi chương trình của mình để thêm nhân viên thư ký tạm thời mới 47You run the program to test it 48Bạn nhận được một ngoại lệ 637 nói rằng 499 đối số vị trí được mong đợi, nhưng 400 đã được đưa raThis is because you derived 482 first from 476 and then from 670, so the interpreter is trying to use 404 to initialize the objectOkay, let’s reverse it 49Bây giờ, hãy chạy lại chương trình và xem điều gì sẽ xảy ra 40Now it seems you are missing a 667 parameter, which is necessary to initialize 476, but that parameter doesn’t make sense in the context of a 482 because it’s an 670Maybe implementing 409 will help 41Try it 42That didn’t work either. Okay, it’s time for you to dive into Python’s method resolution order (MRO) to see what’s going on Khi một phương thức hoặc thuộc tính của một lớp được truy cập, Python sử dụng lớp MRO để tìm nó. The MRO is also used by 664 to determine which method or attribute to invoke. You can learn more about 664 in Supercharge Your Classes With Python super()Bạn có thể đánh giá MRO lớp 482 bằng trình thông dịch tương tác>>> 43The MRO shows the order in which Python is going to look for a matching attribute or method. Trong ví dụ này, đây là điều xảy ra khi chúng ta tạo đối tượng 482
Because the parameters don’t match, a 637 exception is raisedYou can bypass the MRO by reversing the inheritance order and directly calling 422 as follows 44Điều đó giải quyết vấn đề tạo đối tượng, nhưng bạn sẽ gặp phải vấn đề tương tự khi cố tính bảng lương. Bạn có thể chạy chương trình để xem vấn đề 45Vấn đề bây giờ là vì bạn đã đảo ngược thứ tự thừa kế, MRO đang tìm phương thức 647 của 424 trước phương thức trong 670. Bạn cần ghi đè 647 trong 482 và gọi triển khai đúng từ đó 46The 697 method directly invokes 429 to ensure that you get the correct result. Bạn có thể chạy lại chương trình để thấy nó hoạt động 47The program now works as expected because you’re forcing the method resolution order by explicitly telling the interpreter which method we want to use Như bạn có thể thấy, đa thừa kế có thể gây nhầm lẫn, đặc biệt khi bạn gặp vấn đề về kim cương Sơ đồ sau đây cho thấy vấn đề kim cương trong hệ thống phân cấp lớp học của bạn Sơ đồ cho thấy vấn đề kim cương với thiết kế lớp hiện tại. 482 uses multiple inheritance to derive from two classes that ultimately also derive from 651. Điều này khiến hai đường dẫn đến lớp cơ sở 651, đây là điều bạn muốn tránh trong thiết kế của mìnhThe diamond problem appears when you’re using multiple inheritance and deriving from two classes that have a common base class. This can cause the wrong version of a method to be called As you’ve seen, Python provides a way to force the right method to be invoked, and analyzing the MRO can help you understand the problem Still, when you run into the diamond problem, it’s better to re-think the design. Bây giờ bạn sẽ thực hiện một số thay đổi để tận dụng đa kế thừa, tránh vấn đề kim cương Các lớp dẫn xuất 651 được sử dụng bởi hai hệ thống khác nhau
This means that everything related to productivity should be together in one module and everything related to payroll should be together in another. You can start making changes to the productivity module 48The 434 module implements the 465 class, as well as the related roles it supports. The classes implement the 474 interface required by the system, but they don’t derived from 651You can do the same with the 421 module 49The 421 module implements the 645, which calculates payroll for the employees. Nó cũng thực hiện các lớp chính sách cho bảng lương. Như bạn có thể thấy, các lớp chính sách không bắt nguồn từ 651 nữaYou can now add the necessary classes to the 694 module 20Mô-đun 470 nhập các chính sách và vai trò từ các mô-đun khác và triển khai các loại 651 khác nhau. Bạn vẫn đang sử dụng đa kế thừa để kế thừa việc triển khai các lớp chính sách tiền lương và vai trò năng suất, nhưng việc triển khai từng lớp chỉ cần xử lý việc khởi tạoNotice that you still need to explicitly initialize the salary policies in the constructors. You probably saw that the initializations of 472 and 476 are identical. Ngoài ra, khởi tạo của 478 và 482 giống nhauYou will not want to have this kind of code duplication in more complex designs, so you have to be careful when designing class hierarchies Đây là sơ đồ UML cho thiết kế mới Sơ đồ hiển thị các mối quan hệ để xác định 476 và 482 bằng cách sử dụng đa thừa kế, nhưng tránh được vấn đề kim cươngBạn có thể chạy chương trình và xem nó hoạt động như thế nào 21Bạn đã thấy cách hoạt động của thừa kế và đa thừa kế trong Python. Bây giờ bạn có thể khám phá chủ đề sáng tác Loại bỏ các quảng cáoComposition in PythonComposition is an object oriented design concept that models a has a relationship. Trong thành phần, một lớp được gọi là hỗn hợp chứa một đối tượng của một lớp khác được gọi là thành phần. In other words, a composite class has a component of another class Thành phần cho phép các lớp tổng hợp sử dụng lại việc triển khai các thành phần mà nó chứa. Lớp tổng hợp không kế thừa giao diện lớp thành phần, nhưng nó có thể tận dụng việc triển khai của nó Mối quan hệ thành phần giữa hai lớp được coi là liên kết lỏng lẻo. Điều đó có nghĩa là những thay đổi đối với lớp thành phần hiếm khi ảnh hưởng đến lớp tổng hợp và những thay đổi đối với lớp tổng hợp không bao giờ ảnh hưởng đến lớp thành phần This provides better adaptability to change and allows applications to introduce new requirements without affecting existing code Khi xem xét hai thiết kế phần mềm cạnh tranh, một dựa trên tính kế thừa và một dựa trên thành phần, giải pháp thành phần thường là linh hoạt nhất. Bây giờ bạn có thể xem cách sáng tác hoạt động You’ve already used composition in our examples. Nếu bạn nhìn vào lớp 651, bạn sẽ thấy rằng nó chứa hai thuộc tính
Hai thuộc tính này là các đối tượng mà lớp 651 có. Do đó, bạn có thể nói rằng một 651 có một 648 và có một tênAnother attribute for an 651 might be an 458 22You implemented a basic address class that contains the usual components for an address. You made the 459 attribute optional because not all addresses will have that componentYou implemented 460 to provide a pretty representation of an 458. Bạn có thể thấy cách triển khai này trong trình thông dịch tương tác>>> 23When you 462 the 463 variable, the special method 460 is invoked. Vì bạn đã quá tải phương thức để trả về một chuỗi được định dạng dưới dạng địa chỉ, nên bạn sẽ có một biểu diễn đẹp, dễ đọc. Operator and Function Overloading in Custom Python Classes gives a good overview of the special methods available in classes that can be implemented to customize the behavior of your objectsYou can now add the 458 to the 651 class through composition 24Bây giờ, bạn khởi tạo thuộc tính 463 thành 468 để biến nó thành tùy chọn, nhưng bằng cách đó, giờ đây bạn có thể gán một 458 cho một 651. Cũng lưu ý rằng không có tham chiếu nào trong mô-đun 694 đến mô-đun 472Thành phần là một mối quan hệ kết hợp lỏng lẻo thường không yêu cầu lớp tổng hợp phải có kiến thức về thành phần Sơ đồ UML thể hiện mối quan hệ giữa 651 và 458 trông như thế nàyThe diagram shows the basic composition relationship between 651 and 458Bây giờ bạn có thể sửa đổi lớp 645 để tận dụng thuộc tính 463 trong 651 25Bạn kiểm tra xem đối tượng 694 có địa chỉ không, nếu có thì in ra. You can now modify the program to assign some addresses to the employees 26Bạn đã thêm một vài địa chỉ vào các đối tượng 481 và 482. Khi bạn chạy chương trình, bạn sẽ thấy các địa chỉ được in 27Lưu ý cách đầu ra bảng lương cho các đối tượng 481 và 482 hiển thị địa chỉ nơi séc được gửiLớp 651 tận dụng việc triển khai lớp 458 mà không cần biết đối tượng 458 là gì hoặc nó được biểu diễn như thế nào. Kiểu thiết kế này linh hoạt đến mức bạn có thể thay đổi lớp 458 mà không ảnh hưởng đến lớp 651Loại bỏ các quảng cáoThiết kế linh hoạt với bố cụcThành phần linh hoạt hơn thừa kế vì nó mô hình hóa mối quan hệ kết hợp lỏng lẻo. Các thay đổi đối với một lớp thành phần có ảnh hưởng tối thiểu hoặc không ảnh hưởng đến lớp tổng hợp. Thiết kế dựa trên thành phần phù hợp hơn để thay đổi You change behavior by providing new components that implement those behaviors instead of adding new classes to your hierarchy Take a look at the multiple inheritance example above. Imagine how new payroll policies will affect the design. Try to picture what the class hierarchy will look like if new roles are needed. As you saw before, relying too heavily on inheritance can lead to class explosion The biggest problem is not so much the number of classes in your design, but how tightly coupled the relationships between those classes are. Tightly coupled classes affect each other when changes are introduced In this section, you are going to use composition to implement a better design that still fits the requirements of the 645 and the 465You can start by implementing the functionality of the 465 28The 465 class defines some roles using a string identifier mapped to a role class that implements the role. It exposes a 494 method that, given a role identifier, returns the role type object. If the role is not found, then a 495 exception is raisedIt also exposes the previous functionality in the 496 method, where given a list of employees it tracks the productivity of those employeesYou can now implement the different role classes 29Each of the roles you implemented expose a 497 that takes the number of 475 worked. The methods return a string representing the dutiesThe role classes are independent of each other, but they expose the same interface, so they are interchangeable. You’ll see later how they are used in the application Now, you can implement the 645 for the application 50 645 lưu giữ cơ sở dữ liệu nội bộ về các chính sách trả lương cho từng nhân viên. It exposes a 201 that, given an employee 648, returns its payroll policy. If a specified 648 doesn’t exist in the system, then the method raises a 495 exceptionThe implementation of 647 works the same as before. It takes a list of employees, calculates the payroll, and prints the resultsYou can now implement the payroll policy classes 51You first implement a 206 class that serves as a base class for all the payroll policies. This class tracks the 674, which is common to all payroll policiesThe other policy classes derive from 206. We use inheritance here because we want to leverage the implementation of 206. Also, 210, 211, and 212 are a 206 210 is initialized with a 667 value that is then used in 647. 211 is initialized with the 675, and implements 647 by leveraging the base class 674The 212 class derives from 210 because it wants to inherit its implementation. It is initialized with the 667 parameters, but it also requires a 224 parameterThe 224 is used to calculate the 226, which is implemented as a property so it gets calculated when requested. In the example, we are assuming that a sale happens every 5 hours worked, and the 226 is the number of sales times the 224 value 212 implements the 647 method by first leveraging the implementation in 210 and then adding the calculated commissionYou can now add an 232 class to manage employee addresses 52The 232 class keeps an internal database of 458 objects for each employee. It exposes a 235 method that returns the address of the specified employee 648. If the employee 648 doesn’t exist, then it raises a 495Việc triển khai lớp 458 vẫn giống như trước đây 22Lớp quản lý các thành phần địa chỉ và cung cấp một biểu diễn đẹp về địa chỉ Cho đến nay, các lớp mới đã được mở rộng để hỗ trợ nhiều chức năng hơn, nhưng không có thay đổi đáng kể nào đối với thiết kế trước đó. Điều này sẽ thay đổi với thiết kế của mô-đun 470 và các lớp của nóBạn có thể bắt đầu bằng cách triển khai một lớp 241 54 241 theo dõi tất cả nhân viên trong công ty. Đối với mỗi nhân viên, nó theo dõi 648, 649 và 245. Nó có một phiên bản của 465, 645 và 232. These instances are used to create employeesNó hiển thị thuộc tính 249 trả về danh sách nhân viên. Các đối tượng 651 được tạo trong một phương thức nội bộ 251. Notice that you don’t have different types of 651 classes. Bạn chỉ cần triển khai một lớp 651 duy nhất 55The 651 class is initialized with the 648, 649, and 463 attributes. It also requires the productivity 245 for the employee and the 259 policyThe class exposes a 488 method that takes the hours worked. Phương pháp này trước tiên truy xuất 261 từ 245. Nói cách khác, nó ủy quyền cho đối tượng 245 thực hiện nhiệm vụ của mìnhTheo cách tương tự, nó ủy quyền cho đối tượng 259 để theo dõi công việc 475. The 259, as you saw, uses those hours to calculate the payroll if neededSơ đồ sau đây cho thấy thiết kế thành phần được sử dụng The diagram shows the design of composition based policies. Có một 651 duy nhất bao gồm các đối tượng dữ liệu khác như 458 và phụ thuộc vào giao diện 269 và 691 để ủy thác công việc. There are multiple implementations of these interfacesBây giờ bạn có thể sử dụng thiết kế này trong chương trình của mình 56You can run the program to see its output 57Thiết kế này được gọi là thiết kế dựa trên chính sách, trong đó các lớp bao gồm các chính sách và chúng ủy quyền cho các chính sách đó để thực hiện công việc Policy-based design was introduced in the book Modern C++ Design, and it uses template metaprogramming in C++ to achieve the results Python does not support templates, but you can achieve similar results using composition, as you saw in the example above This type of design gives you all the flexibility you’ll need as requirements change. Hãy tưởng tượng bạn cần thay đổi cách tính lương cho một đối tượng trong thời gian chạy Loại bỏ các quảng cáoTùy chỉnh hành vi với thành phầnNếu thiết kế của bạn dựa trên sự kế thừa, bạn cần tìm cách thay đổi loại đối tượng để thay đổi hành vi của nó. With composition, you just need to change the policy the object uses Hãy tưởng tượng rằng 481 của chúng ta đột nhiên trở thành nhân viên tạm thời được trả lương theo giờ. You can modify the object during the execution of the program in the following way 58The program gets the employee list from the 241 and retrieves the first employee, which is the manager we want. Then it creates a new 211 initialized at $55 per hour and assigns it to the manager objectThe new policy is now used by the 645 modifying the existing behavior. You can run the program again to see the result 59The check for Mary Poppins, our manager, is now for $2200 instead of the fixed salary of $3000 that she had per week Notice how we added that business rule to the program without changing any of the existing classes. Consider what type of changes would’ve been required with an inheritance design Bạn sẽ phải tạo một lớp mới và thay đổi loại nhân viên quản lý. Không có khả năng bạn có thể thay đổi chính sách trong thời gian chạy Lựa chọn giữa Kế thừa và Thành phần trong PythonCho đến giờ, bạn đã thấy cách hoạt động của tính kế thừa và thành phần trong Python. Bạn đã thấy rằng các lớp dẫn xuất kế thừa giao diện và triển khai của các lớp cơ sở của chúng. Bạn cũng đã thấy rằng thành phần cho phép bạn sử dụng lại việc triển khai một lớp khác Bạn đã triển khai hai giải pháp cho cùng một vấn đề. Giải pháp đầu tiên sử dụng đa kế thừa và giải pháp thứ hai sử dụng thành phần Bạn cũng đã thấy rằng cách gõ vịt của Python cho phép bạn sử dụng lại các đối tượng với các phần hiện có của chương trình bằng cách triển khai giao diện mong muốn. Trong Python, không cần thiết phải xuất phát từ một lớp cơ sở để các lớp của bạn được sử dụng lại Tại thời điểm này, bạn có thể hỏi khi nào nên sử dụng thừa kế so với thành phần trong Python. Cả hai đều cho phép sử dụng lại mã. Kế thừa và thành phần có thể giải quyết các vấn đề tương tự trong chương trình Python của bạn Lời khuyên chung là sử dụng mối quan hệ tạo ra ít phụ thuộc hơn giữa hai lớp. Mối quan hệ này là thành phần. Tuy nhiên, sẽ có lúc việc kế thừa sẽ có ý nghĩa hơn Các phần sau đây cung cấp một số hướng dẫn để giúp bạn đưa ra lựa chọn đúng đắn giữa kế thừa và thành phần trong Python Kế thừa mô hình Mối quan hệ “Là A”Kế thừa chỉ nên được sử dụng để mô hình hóa một mối quan hệ. Nguyên tắc thay thế của Liskov nói rằng một đối tượng kiểu 6, kế thừa từ 7, có thể thay thế một đối tượng kiểu 7 mà không làm thay đổi các thuộc tính mong muốn của chương trìnhNguyên tắc thay thế Liskov là hướng dẫn quan trọng nhất để xác định xem kế thừa có phải là giải pháp thiết kế phù hợp hay không. Tuy nhiên, câu trả lời có thể không đơn giản trong mọi tình huống. May mắn thay, có một bài kiểm tra đơn giản mà bạn có thể sử dụng để xác định xem thiết kế của mình có tuân theo nguyên tắc thay thế của Liskov hay không Giả sử bạn có một lớp 278 cung cấp cách triển khai và giao diện mà bạn muốn sử dụng lại trong một lớp khác 279. Suy nghĩ ban đầu của bạn là bạn có thể lấy 279 từ 278 và kế thừa cả giao diện và triển khai. Để chắc chắn đây là thiết kế phù hợp, bạn làm theo các bước sau
Nếu bạn có thể biện minh cho cả hai mối quan hệ, thì bạn không bao giờ nên kế thừa các lớp đó từ lớp khác. Hãy xem xét một ví dụ cụ thể hơn Bạn có một lớp 286 hiển thị một thuộc tính 287. Bạn cần một lớp 288, cũng có một lớp 287. Có vẻ như 288 là một loại đặc biệt của 286, vì vậy có lẽ bạn có thể lấy từ nó và tận dụng cả giao diện và triển khaiTrước khi bắt đầu triển khai, bạn sử dụng nguyên tắc thay thế Liskov để đánh giá mối quan hệ Một 288 là một 286 vì diện tích của nó được tính từ tích của 294 nhân với 295 của nó. Ràng buộc là 296 và 297 phải bằng nhauNó có ý nghĩa. Bạn có thể biện minh cho mối quan hệ và giải thích tại sao ________ 6288 lại là ________ 6286. Hãy đảo ngược mối quan hệ để xem nó có hợp lý không Một 286 là một 288 vì diện tích của nó được tính từ tích của 294 nhân với 295 của nó. Sự khác biệt là 504 và 505 có thể thay đổi độc lậpNó cũng có ý nghĩa. Bạn có thể biện minh cho mối quan hệ và mô tả các ràng buộc đặc biệt cho mỗi lớp. Đây là một dấu hiệu tốt rằng hai lớp này sẽ không bao giờ xuất phát từ nhau Bạn có thể đã thấy các ví dụ khác dẫn xuất 288 từ 286 để giải thích quyền thừa kế. Bạn có thể hoài nghi với bài kiểm tra nhỏ bạn vừa làm. Đủ công bằng. Hãy viết một chương trình minh họa vấn đề với việc lấy 288 từ 286Đầu tiên, bạn thực hiện 286. Bạn thậm chí sẽ đóng gói các thuộc tính để đảm bảo rằng tất cả các ràng buộc đều được đáp ứng 20Lớp 286 được khởi tạo với một 295 và một 294, và nó cung cấp một thuộc tính 287 trả về diện tích. 295 và 294 được đóng gói để tránh thay đổi chúng trực tiếpBây giờ, bạn lấy 288 từ 286 và ghi đè giao diện cần thiết để đáp ứng các ràng buộc của một 288 21Lớp 288 được khởi tạo với một 521, được sử dụng để khởi tạo cả hai thành phần của lớp cơ sở. Bây giờ, bạn viết một chương trình nhỏ để kiểm tra hành vi 22Chương trình tạo một 286 và một 288 và khẳng định rằng 287 của chúng được tính toán chính xác. Bạn có thể chạy chương trình và thấy rằng mọi thứ là 525 cho đến nay 23Chương trình thực thi chính xác, vì vậy có vẻ như 288 chỉ là trường hợp đặc biệt của 286Sau này, bạn cần hỗ trợ thay đổi kích thước đối tượng 286, vì vậy bạn thực hiện các thay đổi thích hợp cho lớp 24 529 lấy 530 và 531 cho đối tượng. Bạn có thể thêm đoạn mã sau vào chương trình để xác minh rằng nó hoạt động chính xác 25Bạn thay đổi kích thước đối tượng hình chữ nhật và xác nhận rằng khu vực mới là chính xác. Bạn có thể chạy chương trình để xác minh hành vi 23Xác nhận vượt qua và bạn thấy rằng chương trình chạy chính xác Vì vậy, điều gì sẽ xảy ra nếu bạn thay đổi kích thước một hình vuông? 27Bạn chuyển các tham số tương tự cho 533 mà bạn đã sử dụng với 534 và in vùng. Khi bạn chạy chương trình, bạn sẽ thấy 28Chương trình cho thấy khu vực mới là 535 giống như đối tượng 534. Vấn đề bây giờ là đối tượng 532 không còn đáp ứng ràng buộc của lớp 288 rằng 295 và 294 phải bằng nhauLàm thế nào bạn có thể khắc phục vấn đề đó? . Bạn có thể ghi đè 529 trong 532 và bỏ qua tham số 294, nhưng điều đó sẽ gây nhầm lẫn cho những người đang xem các phần khác của chương trình nơi mà 544 đang được thay đổi kích thước và một số trong số chúng không nhận được các khu vực mong đợi vì chúng thực sự là 545Trong một chương trình nhỏ như chương trình này, có thể dễ dàng phát hiện ra nguyên nhân của hành vi kỳ lạ, nhưng trong một chương trình phức tạp hơn, vấn đề sẽ khó tìm ra hơn Thực tế là nếu bạn có thể biện minh cho mối quan hệ thừa kế giữa hai lớp theo cả hai cách, thì bạn không nên lấy lớp này từ lớp khác Trong ví dụ này, không có nghĩa là 288 kế thừa giao diện và triển khai của 529 từ 286. Điều đó không có nghĩa là các đối tượng 288 không thể thay đổi kích thước. Có nghĩa là giao diện khác vì nó chỉ cần tham số 521Sự khác biệt trong giao diện này biện minh cho việc không xuất phát 288 từ 286 như thử nghiệm ở trên đã khuyênLoại bỏ các quảng cáoTrộn các tính năng với các lớp MixinMột trong những cách sử dụng đa kế thừa trong Python là mở rộng các tính năng của lớp thông qua mixin. Mixin là một lớp cung cấp các phương thức cho các lớp khác nhưng không được coi là một lớp cơ sở Mixin cho phép các lớp khác sử dụng lại giao diện và triển khai của nó mà không trở thành siêu lớp. Chúng triển khai một hành vi duy nhất có thể được tổng hợp cho các lớp không liên quan khác. Chúng tương tự như thành phần nhưng chúng tạo ra một mối quan hệ mạnh mẽ hơn Giả sử bạn muốn chuyển đổi các đối tượng thuộc một số loại nhất định trong ứng dụng của mình thành biểu diễn từ điển của đối tượng. Bạn có thể cung cấp phương thức 553 trong mọi lớp mà bạn muốn hỗ trợ tính năng này, nhưng việc triển khai 553 có vẻ rất giống nhauĐây có thể là một ứng cử viên sáng giá cho mixin. Bạn bắt đầu bằng cách sửa đổi một chút lớp 651 từ ví dụ về thành phần 29Sự thay đổi là rất nhỏ. Bạn vừa thay đổi thuộc tính 245 và 259 thành nội bộ bằng cách thêm dấu gạch dưới ở đầu vào tên của chúng. Bạn sẽ sớm thấy tại sao bạn lại thực hiện thay đổi đóBây giờ, bạn thêm lớp 558 10Lớp 558 hiển thị phương thức 553 trả về biểu diễn của chính nó dưới dạng từ điển. Phương pháp này được triển khai dưới dạng hiểu 561 có nội dung: “Tạo ánh xạ từ điển 562 đến 563 cho mỗi mục trong 564 nếu 562 không phải là nội bộ. ”Ghi chú. Đây là lý do tại sao chúng tôi tạo các thuộc tính vai trò và bảng lương bên trong lớp 651, bởi vì chúng tôi không muốn trình bày chúng trong từ điểnNhư bạn đã thấy ở phần đầu, việc tạo một lớp kế thừa một số thành viên từ 631 và một trong những thành viên đó là 629, về cơ bản là ánh xạ tất cả các thuộc tính trong một đối tượng với giá trị của chúngBạn duyệt qua tất cả các mục trong 629 và lọc ra những mục có tên bắt đầu bằng dấu gạch dưới bằng cách sử dụng 570 571 kiểm tra giá trị đã chỉ định. Nếu giá trị là một 631, thì nó sẽ xem liệu nó cũng có thành viên 553 hay không và sử dụng nó để đại diện cho đối tượng. Mặt khác, nó trả về một biểu diễn chuỗi. Nếu giá trị không phải là 631, thì nó chỉ trả về giá trịBạn có thể sửa đổi lớp 651 để hỗ trợ mixin này 11Tất cả những gì bạn phải làm là kế thừa 558 để hỗ trợ chức năng. Sẽ rất tuyệt nếu hỗ trợ chức năng tương tự trong lớp 458, vì vậy thuộc tính 578 được biểu diễn theo cùng một cách 12Bạn áp dụng mixin cho lớp 458 để hỗ trợ tính năng. Bây giờ, bạn có thể viết một chương trình nhỏ để kiểm tra nó 13Chương trình triển khai một 580 chuyển đổi từ điển thành chuỗi JSON bằng cách sử dụng thụt đầu dòng để đầu ra trông đẹp hơnSau đó, nó lặp qua tất cả các nhân viên, in biểu diễn từ điển được cung cấp bởi 553. Bạn có thể chạy chương trình để xem đầu ra của nó 14Bạn đã tận dụng việc triển khai 558 trong cả hai lớp 651 và 458 ngay cả khi chúng không liên quan. Bởi vì 558 chỉ cung cấp hành vi, nó dễ dàng sử dụng lại với các lớp khác mà không gây ra vấn đềLoại bỏ các quảng cáoThành phần cho Mô hình Mối quan hệ “Có A”Các mô hình thành phần a có mối quan hệ. Với thành phần, một lớp 602 có một thể hiện của lớp 603 và có thể tận dụng việc triển khai nó. Lớp 603 có thể được sử dụng lại trong các lớp khác hoàn toàn không liên quan đến lớp 602Trong ví dụ thành phần ở trên, lớp 651 có một đối tượng 458. 458 thực hiện tất cả các chức năng để xử lý địa chỉ và nó có thể được sử dụng lại bởi các lớp khácCác lớp khác như 441 hoặc 594 có thể sử dụng lại 458 mà không liên quan đến 651. Họ có thể tận dụng cùng một triển khai để đảm bảo rằng các địa chỉ được xử lý một cách nhất quán trên ứng dụngMột vấn đề bạn có thể gặp phải khi sử dụng thành phần là một số lớp của bạn có thể bắt đầu phát triển bằng cách sử dụng nhiều thành phần. Các lớp của bạn có thể yêu cầu nhiều tham số trong hàm tạo chỉ để truyền vào các thành phần mà chúng được tạo thành. Điều này có thể làm cho các lớp học của bạn khó sử dụng Một cách để tránh vấn đề là sử dụng Factory Method để xây dựng các đối tượng của bạn. Bạn đã làm điều đó với ví dụ thành phần Nếu bạn nhìn vào việc triển khai lớp 241, bạn sẽ nhận thấy rằng nó sử dụng 251 để xây dựng một đối tượng 651 với các tham số phù hợpThiết kế này sẽ hoạt động, nhưng lý tưởng nhất là bạn có thể xây dựng một đối tượng 651 chỉ bằng cách chỉ định một 648, ví dụ như 202Những thay đổi sau đây có thể cải thiện thiết kế của bạn. Bạn có thể bắt đầu với mô-đun 434 15Trước tiên, bạn tạo nội bộ lớp 204, sau đó cung cấp biến nội bộ 205 cho mô-đun. Bạn đang thông báo với các nhà phát triển khác rằng họ không nên tạo hoặc sử dụng trực tiếp 204. Thay vào đó, bạn cung cấp hai chức năng, 207 và 481, làm giao diện chung cho mô-đun. Đây là những gì các mô-đun khác nên sử dụngĐiều bạn đang nói là 204 là một Singleton và chỉ nên có một đối tượng được tạo từ nóBây giờ, bạn có thể làm tương tự với mô-đun 421 16Một lần nữa, bạn tạo nội bộ 211 và cung cấp giao diện công khai cho nó. Ứng dụng sẽ sử dụng giao diện công khai để lấy chính sách và tính lươngBây giờ bạn sẽ làm tương tự với mô-đun 472 17Về cơ bản, bạn đang nói rằng chỉ nên có một 213, một 211 và một 204. Một lần nữa, mẫu thiết kế này được gọi là mẫu thiết kế Singleton, rất hữu ích cho các lớp chỉ nên có một thể hiện duy nhất.Bây giờ, bạn có thể làm việc trên mô-đun 470. Bạn cũng sẽ tạo một Singleton trong số 217, nhưng bạn sẽ thực hiện một số thay đổi bổ sung 18Trước tiên, bạn nhập các hàm và lớp có liên quan từ các mô-đun khác. 217 được tạo nội bộ và ở dưới cùng, bạn tạo một phiên bản duy nhất. Phiên bản này là công khai và là một phần của giao diện vì bạn sẽ muốn sử dụng nó trong ứng dụngBạn đã thay đổi thuộc tính 219 thành một từ điển trong đó khóa là nhân viên 648 và giá trị là thông tin nhân viên. Bạn cũng đã sử dụng một phương thức 221 để trả về thông tin cho nhân viên được chỉ định 222Thuộc tính 223 hiện sắp xếp các khóa để trả lại cho nhân viên được sắp xếp theo 648 của họ. Bạn đã thay thế phương thức đã xây dựng các đối tượng 651 bằng các lệnh gọi trực tiếp đến bộ khởi tạo 651Lớp 651 hiện được khởi tạo với 648 và sử dụng các hàm công khai có trong các mô-đun khác để khởi tạo các thuộc tính của nóBây giờ bạn có thể thay đổi chương trình để kiểm tra các thay đổi 19Bạn nhập các hàm có liên quan từ các mô-đun 421 và 434, cũng như lớp 231 và 651. Chương trình sạch hơn vì bạn đã hiển thị giao diện cần thiết và đóng gói cách các đối tượng được truy cậpLưu ý rằng bây giờ bạn có thể tạo một đối tượng 651 trực tiếp chỉ bằng cách sử dụng đối tượng 648 của nó. Bạn có thể chạy chương trình để xem đầu ra của nó 0Chương trình hoạt động giống như trước đây, nhưng bây giờ bạn có thể thấy rằng một đối tượng 651 duy nhất có thể được tạo từ 648 của nó và hiển thị biểu diễn từ điển của nóXem kỹ lớp học 651 1Lớp 651 là một hỗn hợp chứa nhiều đối tượng cung cấp các chức năng khác nhau. Nó chứa một 458 thực hiện tất cả các chức năng liên quan đến nơi nhân viên sống 651 cũng chứa vai trò năng suất do mô-đun 434 cung cấp và chính sách trả lương do mô-đun 421 cung cấp. These two objects provide implementations that are leveraged by the 651 class to track work in the 488 method and to calculate the payroll in the 647 methodBạn đang sử dụng bố cục theo hai cách khác nhau. Lớp 458 cung cấp dữ liệu bổ sung cho 651 trong đó các đối tượng vai trò và bảng lương cung cấp hành vi bổ sungStill, the relationship between 651 and those objects is loosely coupled, which provides some interesting capabilities that you’ll see in the next sectionThành phần để thay đổi hành vi thời gian chạyKế thừa, trái ngược với thành phần, là một mối quan hệ cặp đôi chặt chẽ. With inheritance, there is only one way to change and customize behavior. Method overriding is the only way to customize the behavior of a base class. Điều này tạo ra những thiết kế cứng nhắc, khó thay đổi Mặt khác, thành phần cung cấp một mối quan hệ được kết hợp lỏng lẻo cho phép các thiết kế linh hoạt và có thể được sử dụng để thay đổi hành vi trong thời gian chạy Imagine you need to support a long-term disability (LTD) policy when calculating payroll. Chính sách quy định rằng một nhân viên tại LTD sẽ được trả 60% tiền lương hàng tuần của họ với giả định 40 giờ làm việc Với thiết kế kế thừa, đây có thể là một yêu cầu rất khó hỗ trợ. Adding it to the composition example is a lot easier. Hãy bắt đầu bằng cách thêm lớp chính sách 2Notice that 249 doesn’t inherit 206, but implements the same interface. Điều này là do việc triển khai hoàn toàn khác, vì vậy chúng tôi không muốn kế thừa bất kỳ triển khai nào của 206The 249 initializes 253 to 468, and provides an internal 255 method that raises an exception if the 256 has not been applied. Sau đó, nó cung cấp một phương thức 257 để gán 253Trước tiên, giao diện công khai kiểm tra xem 253 đã được áp dụng chưa, sau đó triển khai chức năng theo chính sách cơ sở đó. Phương thức 260 chỉ ủy quyền cho chính sách cơ sở và 647 sử dụng nó để tính toán 262 và sau đó trả về 60%You can now make a small change to the 651 class 3Bạn đã thêm một phương pháp 264 áp dụng chính sách bảng lương hiện có cho chính sách mới và sau đó thay thế nó. You can now modify the program to apply the policy to an 651 object 4Chương trình truy cập vào 266, được đặt tại chỉ mục 267, tạo đối tượng 249 và áp dụng chính sách cho nhân viên. Khi 647 được gọi, thay đổi được phản ánh. Bạn có thể chạy chương trình để đánh giá đầu ra 5Số tiền séc cho nhân viên Kevin Bacon, là nhân viên bán hàng, hiện là $1080 thay vì $1800. Đó là bởi vì 249 đã được áp dụng cho tiền lươngAs you can see, you were able to support the changes just by adding a new policy and modifying a couple interfaces. Đây là loại linh hoạt mà thiết kế chính sách dựa trên thành phần mang lại cho bạn Lựa chọn giữa Kế thừa và Thành phần trong PythonPython, với tư cách là một ngôn ngữ lập trình hướng đối tượng, hỗ trợ cả kế thừa và thành phần. Bạn đã thấy rằng kế thừa được sử dụng tốt nhất để mô hình hóa một mối quan hệ, trong khi các mô hình thành phần a có một mối quan hệ Đôi khi, thật khó để biết mối quan hệ giữa hai lớp là gì, nhưng bạn có thể làm theo các hướng dẫn sau
Phần kết luậnYou explored inheritance and composition in Python. Bạn đã học về loại mối quan hệ mà thừa kế và thành phần tạo ra. Bạn cũng đã trải qua một loạt bài tập để hiểu cách kế thừa và thành phần được triển khai trong Python Trong bài viết này, bạn đã học cách
đề xuất đọcDưới đây là một số sách và bài viết khám phá sâu hơn về thiết kế hướng đối tượng và có thể hữu ích để giúp bạn hiểu cách sử dụng chính xác tính kế thừa và thành phần trong Python hoặc các ngôn ngữ khác
Đánh dấu là đã hoàn thành Xem ngay Hướng dẫn này có một khóa học video liên quan do nhóm Real Python tạo. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn. Kế thừa và thành phần. Hướng dẫn OOP Python 🐍 Thủ thuật Python 💌 Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python Gửi cho tôi thủ thuật Python » Giới thiệu về Isaac Rodríguez Xin chào, tôi là Isaac. Tôi xây dựng, lãnh đạo và cố vấn cho các nhóm phát triển phần mềm và trong vài năm qua, tôi đã tập trung vào các dịch vụ đám mây và ứng dụng phụ trợ bằng Python cùng với các ngôn ngữ khác. Rất thích nghe từ bạn ở đây tại Real Python » Thông tin thêm về Y-sácMỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là Alex Aldren Joanna Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia Nâng cao kỹ năng Python của bạn » Bậc thầy Kỹ năng Python trong thế giới thực Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia Nâng cao kỹ năng Python của bạn » Bạn nghĩ sao? Đánh giá bài viết này Tweet Chia sẻ Chia sẻ EmailBài học số 1 hoặc điều yêu thích mà bạn đã học được là gì? Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. Nhận các mẹo để đặt câu hỏi hay và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi Mối quan hệ giữa lớp và đối tượng là gì?Lớp là khuôn mẫu cho các đối tượng . Một lớp định nghĩa các thuộc tính đối tượng bao gồm một phạm vi giá trị hợp lệ và một giá trị mặc định. Một lớp cũng mô tả hành vi của đối tượng. Một đối tượng là một thành viên hoặc một "thể hiện" của một lớp.
Sự khác biệt giữa lớp và đối tượng trong python là gì?Đối tượng là một thể hiện của lớp . Tất cả các thành viên dữ liệu và chức năng thành viên của lớp có thể được truy cập với sự trợ giúp của các đối tượng. Khi một lớp được định nghĩa, không có bộ nhớ nào được cấp phát, nhưng bộ nhớ được cấp phát khi nó được khởi tạo (i. e. một đối tượng được tạo ra).
So sánh giữa lớp và đối tượng là gì?Lớp so với đối tượng
. Một đối tượng là một thể hiện của lớp cho phép người lập trình sử dụng các biến và phương thức từ bên trong lớp. Bộ nhớ không được phân bổ cho các lớp
Mối quan hệ giữa các đối tượng lớp và thuộc tính là gì?Một lớp là bản thiết kế của một đối tượng. Một biến của một lớp được gọi là một thể hiện của một lớp hoặc một đối tượng. Một lớp cho phép bạn tạo các loại phức tạp bằng cách nhóm các thuộc tính của nó bằng cách xác định các trường . Để tạo một đối tượng, bạn cần khai báo một biến của một lớp và khởi tạo nó. |