Hướng dẫn composition python - thành phần trăn
Qua các series tự học về Design Pattern, Hôm nay cafedevn chia sẻ cho ace ví dụ và code cụ thể về cách sử dụng Composite design pattern với ngôn ngữ lập trình Python. Nhằm giúp ace hiểu rõ cách sử Pattern này với Python một cách nhanh nhất và áp dụng nó vào thực tế. Show
Nội dung chính
Mixing Features With Mixin Classes Phần code
Composition to Model “Has A” Relationshipmọi lúc mọi nơi tại đây. Composition to Change Run-Time Behavior
Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.
Pinterest This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Inheritance and Composition: A Python OOP Guide Trang chủinheritance and composition in Python. Inheritance and composition are two important concepts in object oriented programming that model the relationship between two classes. They are the building blocks of object oriented design, and they help programmers to write reusable code. Chào thân ái và quyết thắng!:
What Are Inheritance and Composition?Use multiple inheritance in Python and understand its drawbacks and composition are two major concepts in object oriented programming that model the relationship between two classes. They drive the design of an application and determine how the application should evolve as new features are added or requirements change. Use composition to create complex objects What’s Inheritance?Reuse existing code by applying composition models what is called an is a relationship. This means that when you have a 7 class that inherits from a 8 class, you created a relationship where 7 is a specialized version of 8.Change application behavior at run-time through composition Inheritance and composition are two major concepts in object oriented programming that model the relationship between two classes. They drive the design of an application and determine how the application should evolve as new features are added or requirements change.extends is usually added to the arrow. Both of them enable code reuse, but they do it in different ways.is an 1. This means that 2 inherits the interface and implementation of 1, and 2 objects can be used to replace 1 objects in the application.Inheritance models what is called an is a relationship. This means that when you have a 7 class that inherits from a 8 class, you created a relationship where 7 is a specialized version of 8.Inheritance is represented using the Unified Modeling Language or UML in the following way: What’s Composition?Classes are represented as boxes with the class name on top. The inheritance relationship is represented by an arrow from the derived class pointing to the base class. The word extends is usually added to the arrow. is a concept that models a has a relationship. It enables creating complex types by combining objects of other types. This means that a class 03 can contain an object of another class 04. This relationship means that a 03 has a 04.UML đại diện cho bố cục như sau: Thành phần được thể hiện thông qua một dòng với một viên kim cương ở lớp tổng hợp chỉ vào lớp thành phần. Phía tổng hợp có thể thể hiện tính chất của mối quan hệ. Cardinality cho biết số lượng hoặc phạm vi hợp lệ của các trường hợp ____104 mà lớp 03 sẽ chứa.Trong sơ đồ trên, 09 thể hiện rằng lớp 03 chứa một đối tượng loại 04. Cardinality có thể được thể hiện theo những cách sau:
Ví dụ: lớp 2 của bạn có thể được sáng tác bởi một đối tượng khác của loại 19. Thành phần cho phép bạn thể hiện mối quan hệ đó bằng cách nói 2 có 19.has a 19.Thà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, trái ngược với việc kế thừa giao diện và triển khai các lớp khác. Cả hai lớp 2 và 23 đều có thể tận dụng chức năng của 19 thông qua thành phần mà không cần lấy một lớp từ lớp kia.Tổng quan về thừa kế trong PythonTất cả mọi thứ trong Python là một đối tượng. Các mô -đun là đối tượng, định nghĩa lớp và chức năng là đối tượng và tất nhiên, các đối tượng được tạo từ các lớp cũng là đối tượng. Kế thừa là một tính năng cần thiết 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ợ thừa kế và như bạn sẽ thấy sau đó, nó là một trong số ít ngôn ngữ hỗ trợ nhiều kế thừa. Khi bạn viết mã Python bằng các lớp, bạn đang sử dụng kế thừa ngay cả khi bạn không biết bạn sử dụng nó. Hãy cùng xem xét điều đó có nghĩa là gì. Đối tượng siêu lớpCách dễ nhất để thấy sự kế thừa trong Python là nhảy vào vỏ 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ể: >>>
Bạn đã tuyên bố một lớp 25 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 chức năng 26 để liệt kê các thành viên của nó:>>>
Bạn đã tuyên bố một lớp 25 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 chức năng 26 để liệt kê các thành viên của nó:>>>
Bạn đã tuyên bố một lớp 25 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 chức năng 26 để liệt kê các thành viên của nó: 26 Trả về danh sách tất cả các thành viên trong đối tượng được chỉ định. Bạn đã không tuyên bố bất kỳ thành viên nào trong 25, vậy danh sách đến từ đâu? Bạn có thể tìm hiểu bằng cách sử dụng trình thông dịch tương tác:Như 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 >>> class MyClass: ... pass ... 25 như >>> class MyClass: ... pass ... 30 và >>> class MyClass: ... pass ... 31, nhưng mỗi thành viên của lớp >>> class MyClass: ... pass ... 32 cũng có mặt trong >>> class MyClass: ... pass ... 25.Điều này là do mỗi lớp bạn tạo ra trong Python hoàn toàn xuất phát từ 32. Bạn có thể rõ ràng hơn và viết 35, nhưng nó dự phòng và không cần thiết.Ngoại lệ là một ngoại lệ >>>
Bạn đã tuyên bố một lớp 25 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 chức năng 26 để liệt kê các thành viên của nó: 26 Trả về danh sách tất cả các thành viên trong đối tượng được chỉ định. Bạn đã không tuyên bố bất kỳ thành viên nào trong 25, vậy danh sách đến từ đâu? Bạn có thể tìm hiểu bằng cách sử dụng trình thông dịch tương tác:Như 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 25 như 30 và 31, nhưng mỗi thành viên của lớp 32 cũng có mặt trong 25.>>>
Bạn đã tuyên bố một lớp 25 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 chức năng 26 để liệt kê các thành viên của nó:>>> class MyClass: ... pass ... 26 Trả về danh sách tất cả các thành viên trong đối tượng được chỉ định. Bạn đã không tuyên bố bất kỳ thành viên nào trong >>> class MyClass: ... pass ... 25, vậy danh sách đến từ đâu? Bạn có thể tìm hiểu bằng cách sử dụng trình thông dịch tương tác:Như 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 25 như 30 và 31, nhưng mỗi thành viên của lớp 32 cũng có mặt trong 25.Điều này là do mỗi lớp bạn tạo ra trong Python hoàn toàn xuất phát từ 32. Bạn có thể rõ ràng hơn và viết 35, nhưng nó dự phòng và không cần thiết.Ngoại lệ là một ngoại lệ Bạn bắt đầu bằng cách thực hiện một lớp 45 xử lý bảng lương:
45 thực hiện phương pháp 47 lấy bộ sưu tập nhân viên và in 48, 49 và kiểm tra số tiền bằng phương pháp 47 được phơi sáng trên mỗi đối tượng nhân viên.Bây giờ, bạn thực hiện một lớp cơ sở 51 xử lý giao diện chung cho mọi loại nhân viên:
51 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 48 và 49. Những gì bạn đang nói là mỗi 51 phải có 48 được gán cũng như một tên.Hệ thống nhân sự yêu cầu mỗi 51 được xử lý phải cung cấp giao diện 47 trả lại mức lương hàng tuần cho nhân viên. Việc thực hiện giao diện đó khác nhau tùy thuộc vào loại 51.Ví dụ, nhân viên hành chính có mức lương cố định, vì vậy mỗi tuần họ được trả cùng một số tiền: ________số 8Bạn tạo một lớp dẫn xuất 60 kế thừa 51. Lớp được khởi tạo với 48 và 49 theo yêu cầu của lớp cơ sở và bạn sử dụng 64 để 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ề 64 trong Supercharge Các lớp của bạn với Python Super (). 60 cũng yêu cầu tham số khởi tạo 67 đại diện cho số tiền mà nhân viên thực hiện mỗi tuần.Lớp cung cấp phương pháp 47 cần thiết đượ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 67.Công ty cũng sử dụng nhân viên sản xuất được trả theo giờ, vì vậy bạn thêm 70 vào hệ thống nhân sự:
Lớp 70 được khởi tạo với 48 và 49, như lớp cơ sở, cộng với 74 và 75 cần thiết để tính toán bảng lương. Phương pháp 47 được thực hiện bằng cách trả lại thời gian làm việc theo tỷ lệ giờ.Cuối cùng, công ty sử dụng các cộng sự bán hàng được thanh toán thông qua mức lương cố định cộng với một khoản hoa hồng dựa trên doanh số của họ, vì vậy bạn tạo một lớp 77: 0Bạn lấy 77 từ 60 vì cả hai lớp đều có 67 để xem xét. Đồng thời, 77 được khởi tạo với giá trị 82 dựa trên doanh số cho nhân viên. 47 tận dụng việc thực hiện lớp cơ sở để lấy tiền lương 84 và thêm giá trị hoa hồng.Vì 77 xuất phát từ 60, bạn có quyền truy cập trực tiếp vào thuộc tính 67 và bạn có thể triển khai 47 bằng cách sử dụng giá trị của thuộc tính đó.Vấn đề với việc truy cập trực tiếp vào tài sản là nếu việc thực hiện 89 thay đổi, thì bạn cũng sẽ phải thay đổi việc thực hiện 90. Nó tốt hơ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ần thiết.Bạn đã tạo hệ thống phân cấp hạng nhất của bạn 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 kế thừa của các lớp. Các lớp dẫn xuất thực hiện giao diện 91, được yêu cầu bởi 45. Việc triển khai 93 yêu cầu các đối tượng 94 được thông qua có chứa một triển khai 48, 49 và 97.Các giao diện được biểu diễn tương tự như các lớp có giao diện từ phía trên tên giao diện. Tên giao diện thường được tiền tố với vốn 98.interface above the interface name. Interface names are usually prefixed with a capital 98.Ứng dụng tạo ra nhân viên của mình và chuyển họ đến hệ thống bảng lương để xử lý bảng lương: 1Bạn có thể chạy chương trình trong dòng lệnh và xem kết quả: 2Chương trình tạo ra ba đối tượng nhân viên, một cho mỗi lớp dẫn xuất. Sau đó, nó tạo ra hệ thống bảng lương và chuyển danh sách nhân viên cho phương thức 47 của nó, tính toán bảng lương cho mỗi nhân viên và in kết quả.Lưu ý cách lớp cơ sở 51 không xác định phương thức 47. Điều này có nghĩa là nếu bạn đã tạo một đối tượng 51 đơn giản và chuyển nó đến 45, thì bạn sẽ gặp lỗi. Bạn có thể thử nó trong trình thông dịch tương tác Python:>>> 3Mặc dù bạn có thể khởi tạo một đối tượng 51, đối tượng có thể được sử dụng bởi 45. Tại sao? Bởi vì nó có thể 47 cho một 51. Để đáp ứng các yêu cầu của 45, bạn sẽ muốn chuyển đổi lớp 51, hiện là một lớp cụ thể, thành một lớp trừu tượng. Bằng cách đó, không có nhân viên nào chỉ là một 51, nhưng một trong đó thực hiện 47.Các lớp học cơ sở trừu tượng trong PythonLớp 51 trong ví dụ trên là cái đượ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ờ khởi tạo. Python cung cấp mô -đun 13 để xác định các lớp cơ sở trừu tượng.Bạn có thể sử dụng các dấu gạch dưới hàng đầu trong tên lớp của mình để truyền đạt rằng các đối tượng của lớp đó không nên được tạo. Undercores cung cấp một cách thân thiện để ngăn chặn việc lạm dụng mã của bạn, nhưng họ không ngăn cản người dùng háo hức tạo ra các trường hợp của lớp đó. Mô -đun 13 trong Thư viện tiêu chuẩn Python cung cấp chức năng để ngăn chặn việc tạo các đối tượng từ các lớp cơ sở trừu tượng.Bạn có thể sửa đổi việc triển khai lớp 51 để đảm bảo rằng nó có thể được khởi tạo: 4Bạn lấy 51 từ 17, làm cho nó trở thành một lớp cơ sở trừu tượng. Sau đó, bạn trang trí phương pháp 47 với bộ trang trí 19.Thay đổi này có hai tác dụng phụ đẹp:
Bạn có thể thấy rằng các đối tượng thuộc loại 51 có thể được tạo bằng cách sử dụng trình thông dịch tương tác:>>> 5Đầu ra cho thấy lớp không thể được khởi tạo vì nó chứa một phương pháp trừu tượng 97. 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úng.Kế thừa thực hiện so với kế thừa giao diệnKhi bạn lấy một lớp này từ một lớp khác, lớp dẫn xuất 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 thực hiện nhiều giao diện, vì vậy 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. Ngôn ngữ lập trình hiện đại được thiết kế với khái niệm cơ bản này trong tâm trí. 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 phải tuyên bố rõ ràng giao diện. Bất kỳ đối tượng nào thực hiện giao diện mong muốn có thể được sử dụng thay cho một đố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 như một con vịt, thì nó là một con vịt.duck typing. Duck typing is usually explained as “if it behaves like a duck, then it’s a duck.” Để minh họa điều này, bây giờ bạn sẽ thêm một lớp 26 vào ví dụ trên mà không có nguồn gốc từ 51: 6Lớp 26 không có nguồn gốc từ 51, nhưng nó phơi bày cùng một giao diện theo yêu cầu của 45. 93 yêu cầu một danh sách các đối tượng thực hiện giao diện sau:
Tất cả các yêu cầu này được đáp ứng bởi lớp 26, vì vậy 45 vẫn có thể tính toán bảng lương của nó.Bạn có thể sửa đổi chương trình để sử dụng lớp 26: 7Chương trình tạo ra một đối tượng 26 và thêm nó vào danh sách được xử lý bởi 45. Bây giờ bạn có thể chạy chương trình và xem đầu ra của nó: 8Như bạn có thể thấy, 45 vẫn có thể xử lý đối tượng mới vì nó đáp ứng giao diện mong muốn.Vì bạn không phải xuất phát từ một lớp cụ thể để các đối tượng của bạn được chương trình có thể sử dụng lại, bạn có thể hỏi tại sao bạn nên sử dụng kế thừa thay vì chỉ triển khai giao diện mong muốn. Các quy tắc sau 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 46 và sau đó sửa đổi mô -đun 21 thành trạng thái ban đầu của nó: 9Bạn đã loại bỏ việc nhập mô -đun 13 vì lớp 51 không cần phải trừu tượng. Bạn cũng đã loại bỏ phương thức Tóm tắt 97 khỏi nó vì nó không cung cấp bất kỳ triển khai nào.Về cơ bản, bạn đang kế thừa việc thực hiện các thuộc tính 48 và 49 của lớp 51 trong các lớp dẫn xuất của bạn. Vì 47 chỉ là một giao diện cho phương thức 93, bạn không cần phải thực hiện nó trong lớp cơ sở 51.Lưu ý cách lớp 77 xuất phát từ 60. Điều này có nghĩa là 77 kế thừa việc triển khai và giao diện của 60. Bạn có thể thấy phương pháp 90 tận dụng việc triển khai lớp cơ sở như thế nào vì nó dựa vào kết quả từ 62 để thực hiện phiên bản của riêng mình.Vấn đề vụ nổ lớpNếu bạn không cẩn thận, 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à duy trì. Điều này được gọi là vấn đề vụ nổ lớp.class explosion problem. Bạn bắt đầu xây dựng một hệ thống phân cấp lớp gồm 51 Các loại được sử dụng bởi 45 để tính toán 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 đó, vì vậy chúng có thể được sử dụng với 65 mới. 65 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 các yêu cầu đó, bạn bắt đầu thấy rằng 51 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 ngoài mô -đun 21 vì bây giờ chúng cũng được sử dụng bởi 65.Bạn tạo một mô -đun 70 và di chuyển các lớp ở đó: 0Việc triển khai vẫn giữ nguyên, nhưng bạn chuyển các lớp sang mô -đun 94. Bây giờ, bạn thay đổi chương trình của mình để hỗ trợ thay đổi: 1Bạn chạy chương trình và xác minh rằng nó vẫn hoạt động: 2Với mọi thứ tại chỗ, bạn bắt đầu thêm các lớp mới: 3Đầu tiên, bạn thêm một lớp 72 xuất phát từ 60. Lớp hiển thị một phương pháp 74 sẽ được sử dụng bởi hệ thống năng suất. Phương pháp lấy 75 nhân viên đã làm việc.Sau đó, bạn thêm 76, 77 và 78 và sau đó thực hiện giao diện 74, do đó chúng có thể được sử dụng bởi hệ thống năng suất.Bây giờ, bạn có thể thêm lớp 80: 4Lớp học theo dõi nhân viên theo phương pháp 81 lấy danh sách nhân viên và số giờ để 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: 5Chương trình tạo ra một danh sách các nhân viên thuộc các loại khác nhau. 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 toán bảng lương của họ. Bạn có thể chạy chương trình để xem đầu ra: 6Chương trình cho thấy 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 mỗi 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 yêu cầu mới đến, 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 đề vụ nổ của 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à duy trì. Biểu đồ 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 trong số lượng các lớp với thiết kế này. Kế thừa nhiều lớpPython là một trong số ít các ngôn ngữ lập trình hiện đại hỗ trợ nhiều kế thừa. Nhiều kế thừa là khả năng lấy một lớp từ nhiều lớp cơ sở cùng một lúc. Nhiều kế thừa có tiếng xấu đến mức mà hầu hết các ngôn ngữ lập trình hiện đại không ủng hộ 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 đó thực hiện nhiều giao diện, do đó 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 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 thực hiện một lớp bằng cách trực tiếp xuất phát từ nó. Bạn có thể triển khai nhiều giao diện, nhưng bạn có thể kế thừa việc triển khai nhiều lớp. Hạn chế 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 học của mình với ít phụ thuộc hơn vào nhau. Bạn sẽ thấy sau trong bài viết này rằng bạn có thể tận dụng nhiều triển khai thông qua thành phần, điều này làm cho phần mềm linh hoạt hơn. Tuy nhiên, phần này là về nhiều kế thừa, vì vậy, hãy để xem cách thức hoạt động của nó. Hóa ra đôi khi các thư ký tạm thời được thuê khi có quá nhiều giấy tờ để làm. Lớp 82 thực hiện vai trò của 76 trong bối cảnh 65, nhưng đối với mục đích biên chế, đó là một 70.Bạn nhìn vào thiết kế lớp học của bạn. Nó đã phát triển một chút, nhưng bạn vẫn có thể hiểu nó hoạt động như thế nào. Có vẻ như bạn có hai tùy chọn:
Sau đó, bạn nhớ rằng Python hỗ trợ nhiều kế thừa, vì vậy bạn quyết định xuất phát từ cả 76 và 70: 7Python 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: 8Bạn chạy chương trình để kiểm tra nó: 9Bạn nhận được một ngoại lệ 37 nói rằng 99 Các đối số vị trí mà mong đợi, nhưng 00 đã được đưa ra.Điều này là do bạn đã lấy 82 đầu tiên từ 76 và sau đó từ 70, vì vậy trình thông dịch đang cố gắng sử dụng 04 để khởi tạo đối tượng.Được rồi, hãy để Lừa đảo ngược nó: 0Bây giờ, hãy chạy lại chương trình và xem điều gì sẽ xảy ra: 1Bây giờ có vẻ như bạn đang thiếu một tham số 67, điều cần thiết để khởi tạo 76, nhưng tham số đó không có ý nghĩa trong bối cảnh của 82 bởi vì nó là một 70.Có thể triển khai 09 sẽ giúp: 2Thử nó: 3Điều đó cũng không làm việc. Được rồi, đó là thời gian để bạn đi sâu vào thứ tự phân giải phương pháp Python (MRO) để xem những gì đang diễn ra.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ó. MRO cũng được 64 sử dụng để xác định phương thức hoặc thuộc tính nào để gọi. Bạn có thể tìm hiểu thêm về 64 trong Supercharge Các lớp của bạn với Python Super ().Bạn có thể đánh giá lớp MRO 82 bằng trình thông dịch tương tác:>>> 4MRO hiển thị thứ tự mà Python sẽ tìm kiếm một thuộc tính hoặc phương thức phù hợp. Trong ví dụ, đây là những gì xảy ra khi chúng ta tạo đối tượng 82:
Bởi vì các tham số không phù hợp, một ngoại lệ 37 được nâng lên.Bạn có thể bỏ qua MRO bằng cách đảo ngược thứ tự kế thừa và gọi trực tiếp 22 như sau: 5Điều đó giải quyết vấn đề tạo đối tượng, nhưng bạn sẽ gặp phải một vấn đề tương tự khi cố gắng tính toán bảng lương. Bạn có thể chạy chương trình để xem vấn đề: 6Vấn đề bây giờ là bởi vì bạn đã đảo ngược thứ tự thừa kế, MRO đang tìm phương pháp 47 của 24 trước phương pháp trong 70. Bạn cần ghi đè 47 trong 82 và gọi đúng cách thực hiện từ nó: 7Phương pháp 97 trực tiếp gọi 29 để đảm bảo rằng bạn nhận được kết quả chính xác. Bạn có thể chạy lại chương trình để xem nó hoạt động: 8Chương trình hiện hoạt động như mong đợi bởi vì bạn buộc phải thứ tự giải quyết phương thức bằng cách nói rõ ràng với trình thông dịch mà chúng tôi muốn sử dụng phương pháp nào. Như bạn có thể thấy, nhiều kế thừa có thể gây nhầm lẫn, đặc biệt là khi bạn gặp phải vấn đề kim cương. Biểu đồ sau đây cho thấy vấn đề kim cương trong hệ thống phân cấp lớp của bạn: Sơ đồ cho thấy vấn đề kim cương với thiết kế lớp hiện tại. 82 sử dụng nhiều kế thừa để xuất phát từ hai lớp cuối cùng cũng xuất phát từ 51. Điều này làm cho hai đường dẫn đến lớp cơ sở 51, đó là điều bạn muốn tránh trong các thiết kế của mình.Vấn đề kim cương xuất hiện khi bạn sử dụng nhiều kế thừa và xuất phát từ hai lớp có lớp cơ sở chung. Điều này có thể khiến phiên bản sai của phương thức được gọi. Như bạn đã thấy, Python cung cấp một cách để buộc đúng phương pháp được gọi và phân tích MRO có thể giúp bạn hiểu vấn đề. Tuy nhiên, khi bạn gặp phải vấn đề kim cương, nó tốt hơn là suy nghĩ lại thiết kế. Bây giờ bạn sẽ thực hiện một số thay đổi để tận dụng nhiều kế thừa, tránh vấn đề kim cương. Các lớp dẫn xuất 51 được sử dụng bởi hai hệ thống khác nhau:
Điều này có nghĩa là tất cả mọi thứ liên quan đến năng suất nên được cùng nhau trong một mô -đun và mọi thứ liên quan đến bảng lương nên được cùng nhau ở cùng. Bạn có thể bắt đầu thay đổi mô -đun năng suất: 9Mô -đun 34 thực hiện lớp 65, cũng như các vai trò liên quan mà nó hỗ trợ. Các lớp thực hiện giao diện 74 theo yêu cầu của hệ thống, nhưng chúng không có nguồn gốc từ 51.Bạn có thể làm tương tự với mô -đun 21: 0Mô -đun 21 thực hiện 45, tính toán bảng lương cho nhân viên. 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 don don bắt nguồn từ 51 nữa.Bây giờ bạn có thể thêm các lớp cần thiết vào mô -đun 94: 1Mô -đun 70 Nhập các chính sách và vai trò từ các mô -đun khác và thực hiện các loại 51 khác nhau. Bạn vẫn đang sử dụng nhiều kế thừa để kế thừa việc thực hiện các lớp chính sách lương và vai trò năng suất, nhưng việc thực hiện từng lớp chỉ cần đối phó với việc khởi tạo.Lưu ý rằng bạn vẫn cần khởi tạo rõ ràng các chính sách lương trong các nhà xây dựng. Bạn có thể thấy rằng các khởi tạo của 72 và 76 là giống hệt nhau. Ngoài ra, các khởi đầu của 78 và 82 là như nhau.Bạn sẽ không muốn có loại sao chép mã này trong các thiết kế phức tạp hơn, vì vậy bạn phải cẩn thận khi thiết kế phân cấp lớp. Ở đây, sơ đồ UML cho thiết kế mới: Sơ đồ cho thấy các mối quan hệ để xác định 76 và 82 bằng cách sử dụng nhiều kế thừa, nhưng tránh được vấn đề kim cương.Bạn có thể chạy chương trình và xem cách thức hoạt động: 2Bạn đã thấy cách thừa kế và nhiều kế thừa hoạt động trong Python. Bây giờ bạn có thể khám phá chủ đề của sáng tác. Thành phần trong PythonThành phần là một khái niệm thiết kế định hướng đối tượng mô hình A có mối quan hệ. Trong thành phần, một lớp được gọi là tổng 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. Nói cách khác, một lớp tổng hợp có một thành phần của một lớp khác. is an object oriented design concept that models a has a relationship. In composition, a class known as composite contains an object of another class known to as component. 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 thực hiện 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à kết hợp lỏng lẻo. Điều đó có nghĩa là các 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à thay đổi thành lớp tổng hợp không bao giờ ảnh hưởng đến lớp thành phần. Điều này cung cấp khả năng thích ứng tốt hơn để thay đổi và cho phép các ứng dụng giới thiệu các yêu cầu mới mà không ảnh hưởng đến mã hiện có. Khi xem xét hai thiết kế phần mềm cạnh tranh, một dựa trên 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ể nhìn vào cách thức thành phần hoạt động. Bạn đã sử dụng thành phần trong các ví dụ của chúng tôi. Nếu bạn nhìn vào lớp 51, 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 51 có. Do đó, bạn có thể nói rằng 51 có 48 và có tên.has an 48 and has a name.Một thuộc tính khác cho 51 có thể là 58: 3Bạn đã triển khai một lớp địa chỉ cơ bản chứa các thành phần thông thường cho một địa chỉ. Bạn đã thực hiện thuộc tính 59 tùy chọn vì không phải tất cả các địa chỉ sẽ có thành phần đó.Bạn đã triển khai 60 để cung cấp một đại diện khá lớn của 58. Bạn có thể thấy việc triển khai này trong trình thông dịch tương tác:>>> 4Khi bạn 62 biến 63, phương pháp đặc biệt 60 được gọi. 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ỉ, bạn sẽ nhận được một đại diện tốt, dễ đọc. Toán tử và quá tải chức năng trong các lớp Python tùy chỉnh cung cấp một cái nhìn tổng quan tốt về các phương thức đặc biệt có sẵn trong các lớp có thể được thực hiện để tùy chỉnh hành vi của các đối tượng của bạn.Bây giờ bạn có thể thêm 58 vào lớp 51 thông qua bố cục: 5Bạn khởi tạo thuộc tính 63 cho 68 ngay bây giờ để làm cho nó tùy chọn, nhưng bằng cách đó, bây giờ bạn có thể gán một 58 cho 51. Cũng lưu ý rằng không có tài liệu tham khảo trong mô -đun 94 đến mô -đun 72.Thành phần là một mối quan hệ được kết hợp lỏng lẻo mà 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 đại diện cho mối quan hệ giữa 51 và 58 trông như thế này:Sơ đồ cho thấy mối quan hệ thành phần cơ bản giữa 51 và 58.Bây giờ bạn có thể sửa đổi lớp 45 để tận dụng thuộc tính 63 trong 51: 6Bạn kiểm tra xem đối tượng 94 có địa chỉ không và nếu có, bạn in nó. Bây giờ bạn có thể sửa đổi chương trình để gán một số địa chỉ cho nhân viên: 7Bạn đã thêm một vài địa chỉ vào các đối tượng 81 và 82. Khi bạn chạy chương trình, bạn sẽ thấy các địa chỉ được in: 8Lưu ý cách đầu ra bảng lương cho các đối tượng 81 và 82 hiển thị các địa chỉ nơi kiểm tra được gửi.Lớp 51 tận dụng việc triển khai lớp 58 mà không có bất kỳ kiến thức nào về đối tượng 58 là gì hoặc cách nó thể hiện. Kiểu thiết kế này linh hoạt đến mức bạn có thể thay đổi lớp 58 mà không có bất kỳ tác động nào đến lớp 51.Thiết kế linh hoạt với bố cụcThành phần linh hoạt hơn sự kế thừa vì nó mô hình hóa một mối quan hệ được ghép nối lỏng lẻo. Các thay đổi đối với một lớp thành phần có hiệu ứng tối thiểu hoặc không có tác dụng đối với lớp tổng hợp. Thiết kế dựa trên bố cục phù hợp hơn để thay đổi. Bạn thay đổi hành vi bằng cách cung cấp các thành phần mới thực hiện các hành vi đó thay vì thêm các lớp mới vào hệ thống phân cấp của bạn. Hãy xem ví dụ về nhiều kế thừa ở trên. Hãy tưởng tượng làm thế nào các chính sách biên chế mới sẽ ảnh hưởng đến thiết kế. Cố gắng hình dung phân cấp lớp sẽ trông như thế nào nếu cần vai trò mới. Như bạn đã thấy trước đây, việc phụ thuộc quá nhiều vào thừa kế có thể dẫn đến vụ nổ giai cấp. Vấn đề lớn nhất không phải là số lượng các lớp trong thiết kế của bạn, nhưng kết hợp chặt chẽ các mối quan hệ giữa các lớp đó. Các lớp kết hợp chặt chẽ ảnh hưởng đến nhau khi thay đổi được giới thiệu. Trong phần này, bạn sẽ sử dụng thành phần để thực hiện một thiết kế tốt hơn vẫn phù hợp với các yêu cầu của 45 và 65.Bạn có thể bắt đầu bằng cách thực hiện chức năng của 65: 9Lớp 65 xác định một số vai trò bằng cách sử dụng một định danh chuỗi được ánh xạ tới một lớp vai trò thực hiện vai trò. Nó phơi bày một phương thức 94, với một định danh vai trò, trả về đối tượng loại vai trò. Nếu vai trò không được tìm thấy, thì ngoại lệ 95 được nâng lên.Nó cũng phơi bày các chức năng trước đó trong phương pháp 96, trong đó đưa ra danh sách nhân viên, nó theo dõi năng suất của những nhân viên đó.Bây giờ bạn có thể thực hiện các lớp vai trò khác nhau: 0Mỗi vai trò bạn đã thực hiện để lộ một 97 có số lượng 75 hoạt động. Các phương pháp trả về một chuỗi đại diện cho các nhiệm vụ.Các lớp vai trò độc lập với nhau, nhưng chúng phơi bày cùng một giao diện, vì vậy chúng có thể hoán đổi cho nhau. Bạn sẽ thấy sau đó chúng được sử dụng trong ứng dụng như thế nào. Bây giờ, bạn có thể triển khai 45 cho ứng dụng: 1 45 giữ một cơ sở dữ liệu nội bộ về chính sách biên chế cho mỗi nhân viên. Nó phơi bày một 01 rằng, với một nhân viên 48, trả lại chính sách biên chế của mình. Nếu một 48 được chỉ định không tồn tại trong hệ thống, thì phương thức này sẽ tăng ngoại lệ 95.Việc thực hiện 47 hoạt động giống như trước đây. Nó lấy một danh sách các nhân viên, tính toán bảng lương và in kết quả.Bây giờ bạn có thể thực hiện các lớp chính sách bảng lương: 2Trước tiên, bạn thực hiện một lớp 06 phục vụ như một lớp cơ sở cho tất cả các chính sách biên chế. Lớp này theo dõi 74, phổ biến cho tất cả các chính sách bảng lương.Các lớp chính sách khác xuất phát từ 06. Chúng tôi sử dụng kế thừa ở đây vì chúng tôi muốn tận dụng việc thực hiện 06. Ngoài ra, 10, 11 và 12 là 06.are a 06. 10 được khởi tạo với giá trị 67 sau đó được sử dụng trong 47. 11 được khởi tạo với 75 và thực hiện 47 bằng cách tận dụng lớp cơ sở 74.Lớp 12 xuất phát từ 10 vì họ muốn kế thừa việc thực hiện. Nó được khởi tạo với các tham số 67, nhưng nó cũng yêu cầu tham số 24. 24 được sử dụng để tính toán 26, được thực hiện như một thuộc tính để nó được tính toán khi được yêu cầu. Trong ví dụ, chúng tôi giả định rằng việc bán hàng xảy ra cứ sau 5 giờ hoạt động và 26 là số lần bán hàng giá trị 24. 12 thực hiện phương pháp 47 bằng cách đầu tiên tận dụng việc thực hiện trong 10 và sau đó thêm hoa hồng được tính toán.Bây giờ bạn có thể thêm một lớp 32 để quản lý địa chỉ nhân viên: 3Lớp 32 giữ cơ sở dữ liệu nội bộ của các đối tượng 58 cho mỗi nhân viên. Nó phơi bày một phương thức 35 trả về địa chỉ của nhân viên được chỉ định 48. Nếu nhân viên 48 không tồn tại, thì nó sẽ tăng 95.Việc triển khai lớp 58 vẫn giống như trước đây: 4Lớp quản lý các thành phần địa chỉ và cung cấp một đại diện khá lớn của một đị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 70 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 41: 5 41 theo dõi tất cả các nhân viên trong công ty. Đối với mỗi nhân viên, nó theo dõi 48, 49 và 45. Nó có một ví dụ của 65, 45 và 32. Những trường hợp này được sử dụng để tạo nhân viên.has an instance of the 65, the 45, and the 32. These instances are used to create employees.Nó phơi bày một tài sản 49 trả về danh sách nhân viên. Các đối tượng 51 được tạo theo phương pháp nội bộ 51. Lưu ý rằng bạn không có các loại lớp 51 khác nhau. Bạn chỉ cần thực hiện một lớp 51 duy nhất: 6Lớp 51 được khởi tạo với các thuộc tính 48, 49 và 63. Nó cũng yêu cầu năng suất 45 cho nhân viên và chính sách 59.Lớp học cho thấy một phương pháp 88 mất nhiều giờ làm việc. Phương pháp này lần đầu tiên lấy 61 từ 45. Nói cách khác, nó ủy thác cho đối tượng 45 để thực hiện nhiệm vụ của mình.Theo cách tương tự, nó giao cho đối tượng 59 để theo dõi công việc 75. 59, như bạn đã thấy, sử dụng những giờ đó để tính toán bảng lương nếu cần.Biểu đồ sau đây cho thấy thiết kế thành phần được sử dụng: Sơ đồ cho thấy thiết kế của các chính sách dựa trên thành phần. Có một 51 bao gồm các đối tượng dữ liệu khác như 58 và phụ thuộc vào giao diện 69 và 91 để ủy thác công việc. Có nhiều triển khai của các giao diện này.Bây giờ bạn có thể sử dụng thiết kế này trong chương trình của mình: 7Bạn có thể chạy chương trình để xem đầu ra của nó: 8Thiết kế này được gọi là thiết kế dựa trên chính sách, nơi các lớp bao gồm các chính sách và họ ủy thác cho các chính sách đó để thực hiện công việc. Thiết kế dựa trên chính sách đã được giới thiệu trong cuốn sách Thiết kế C ++ hiện đại và nó sử dụng metaproming mẫu trong C ++ để đạt được kết quả. Python không hỗ trợ các mẫu, nhưng bạn có thể đạt được kết quả tương tự bằng cách sử dụng thành phần, như bạn đã thấy trong ví dụ trên. Loại thiết kế này cung cấp cho bạn tất cả sự linh hoạt mà bạn sẽ cần khi yêu cầu thay đổi. Hãy tưởng tượng bạn cần thay đổi cách tính toán bảng lương cho một đối tượng trong thời gian chạy. Tùy chỉnh hành vi với bố cụcNếu thiết kế của bạn dựa vào 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ó. Với thành phần, bạn chỉ cần thay đổi chính sách mà đối tượng sử dụng. Hãy tưởng tượng rằng 81 của chúng tôi đột nhiên trở thành một nhân viên tạm thời được trả tiền theo giờ. Bạn có thể sửa đổi đối tượng trong quá trình thực hiện chương trình theo cách sau: 9Chương trình có được danh sách nhân viên từ 41 và lấy nhân viên đầu tiên, đó là người quản lý mà chúng tôi muốn. Sau đó, nó tạo ra một 11 mới được khởi tạo ở mức 55 đô la mỗi giờ và gán nó cho đối tượng Trình quản lý.Chính sách mới hiện được sử dụng bởi 45 sửa đổi hành vi hiện có. Bạn có thể chạy lại chương trình để xem kết quả: 0Kiểm tra Mary Poppins, người quản lý của chúng tôi, hiện có giá 2200 đô la thay vì mức lương cố định là 3000 đô la mà cô ấy có mỗi tuần. Lưu ý cách chúng tôi đã thêm quy tắc kinh doanh vào chương trình mà không thay đổi bất kỳ lớp nào hiện có. Xem xét loại thay đổi nào sẽ được yêu cầu với một thiết kế thừa kế. Bạn sẽ phải tạo ra một lớp mới và thay đổi loại nhân viên của người quản lý. Không có cơ hội bạn có thể thay đổi chính sách vào thời điểm chạy. Lựa chọn giữa thừa kế và thành phần trong PythonCho đến nay, bạn đã thấy cách thừa kế và sáng tác hoạt động trong Python. Bạn đã thấy rằng các lớp có nguồn gốc kế thừa giao diện và triển khai các lớp cơ sở của họ. Bạn cũng đã thấy rằng thành phần cho phép bạn sử dụng lại việc thực hiện một lớp khác. Bạn đã thực hiện hai giải pháp cho cùng một vấn đề. Giải pháp đầu tiên sử dụng nhiều kế thừa và thành phần thứ hai được sử dụng. Bạn cũng đã thấy rằng gõ vịt 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 học của bạn được tái sử dụng. Tại thời điểm này, bạn có thể hỏi khi nào nên sử dụng kế thừa so với thành phần trong Python. Cả hai đều cho phép tái sử dụng mã. Kế thừa và thành phần có thể giải quyết các vấn đề tương tự trong các 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ó những lúc thừa kế 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 cho mô hình “là một mối quan hệ”Kế thừa chỉ nên được sử dụng để mô hình hóa A là một mối quan hệ. Nguyên tắc thay thế Liskov, nói rằng một đối tượng loại 7, kế thừa từ 8, có thể thay thế một đối tượng loại 8 mà không làm thay đổi các thuộc tính mong muốn của chương trình.is a relationship. Liskov’s substitution principle says that an object of type 7, which inherits from 8, can replace an object of type 8 without altering the desirable properties of a program.Nguyên tắc thay thế Liskov, là hướng dẫn quan trọng nhất để xác định xem việc 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 thử nghiệm đơn giản mà bạn có thể sử dụng để xác định xem thiết kế của bạn có tuân theo nguyên tắc thay thế của Liskov hay không. Hãy nói rằng bạn có một lớp 78 cung cấp một triển khai và giao diện mà bạn muốn sử dụng lại trong một lớp khác 79. Suy nghĩ ban đầu của bạn là bạn có thể lấy 79 từ 78 và kế thừa cả giao diện và triển khai. Để chắc chắn rằng đây là thiết kế phù hợp, bạn làm theo các bước luận văn:
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 thừa hưởng các lớp đó từ nhau. Hãy cùng nhìn vào một ví dụ cụ thể hơn. Bạn có một lớp 86 phơi bày một thuộc tính 87. Bạn cần một lớp 88, cũng có 87. Có vẻ như 88 là một loại 86 đặc biệt, vì vậy có lẽ bạn có thể xuất phát từ nó và tận dụng cả giao diện và triển khai.Trước khi bạn nhảy vào việc thực hiện, bạn sử dụng nguyên tắc thay thế Liskov, để đánh giá mối quan hệ. A 88 là 86 vì diện tích của nó được tính toán từ sản phẩm của 94 lần 95 của nó. Hạn chế là 96 và 97 phải bằng nhau.is a 86 because its area is calculated from the product of its 94 times its 95. The constraint is that 96 and 97 must be equal.Nó có ý nghĩa. Bạn có thể biện minh cho mối quan hệ và giải thích tại sao 88 là 86. Hãy để đảo ngược mối quan hệ để xem nó có ý nghĩa không.is a 86.
Let’s reverse the relationship to see if it makes sense.A 86 là 88 vì diện tích của nó được tính toán từ sản phẩm của 94 lần 95 của nó. Sự khác biệt là 04 và 05 có thể thay đổi độc lập.is a 88 because its area is calculated from the product of its 94 times its 95. The difference is that 04 and 05 can change independently.Nó 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 cho thấy hai lớp này không bao giờ nên xuất phát từ nhau. Bạn có thể đã thấy các ví dụ khác xuất phát từ 88 từ 86 để giải thích kế thừa. Bạn có thể hoài nghi với bài kiểm tra nhỏ mà 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 88 từ 86.Đầu tiên, bạn thực hiện 86. Bạn thậm chí sẽ gói gọn các thuộc tính để đảm bảo rằng tất cả các ràng buộc được đáp ứng: 1Lớp 86 được khởi tạo với 95 và 94, và nó cung cấp một thuộc tính 87 trả về khu vực. 95 và 94 được gói gọn để tránh thay đổi chúng trực tiếp.Bây giờ, bạn rút ra 88 từ 86 và ghi đè giao diện cần thiết để đáp ứng các ràng buộc của 88: 2Lớp 88 được khởi tạo bằng 21, đượ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: 3Chương trình tạo ra 86 và 88 và khẳng định rằng 87 của họ đượ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ứ đều là 25 cho đến nay: 4Chương trình thực hiện chính xác, do đó, có vẻ như 88 chỉ là một trường hợp đặc biệt của 86.Sau này, bạn cần hỗ trợ thay đổi kích thước các đối tượng 86, vì vậy bạn thực hiện các thay đổi phù hợp với lớp: 5 29 mất 30 và 31 cho đối tượng. Bạn có thể thêm mã sau vào chương trình để xác minh rằng nó hoạt động chính xác: 6Bạn thay đổi kích thước đối tượng hình chữ nhật và khẳng định 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: 4Khẳng định 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ì xảy ra nếu bạn thay đổi kích thước một hình vuông? Sửa đổi chương trình và cố gắng sửa đổi đối tượng 32: 8Bạn chuyển các tham số tương tự đến 33 mà bạn đã sử dụng với 34 và in khu vực. Khi bạn chạy chương trình bạn thấy: 9Chương trình cho thấy khu vực mới là 35 như đối tượng 34. Vấn đề bây giờ là đối tượng 32 không còn đáp ứng ràng buộc lớp 88 mà 95 và 94 phải bằng nhau.Làm thế nào bạn có thể khắc phục vấn đề đó? Bạn có thể thử một số cách tiếp cận, nhưng tất cả chúng sẽ rất khó xử. Bạn có thể ghi đè 29 trong 32 và bỏ qua tham số 94, nhưng điều đó sẽ gây nhầm lẫn cho những người nhìn vào các phần khác của chương trình trong đó 44 đ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 dự kiến vì chúng thực sự là 45.Trong một chương trình nhỏ như thế 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 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 cả hai cách, bạn không nên lấy một lớp này từ một lớp khác. Trong ví dụ, nó không có ý nghĩa rằng 88 kế thừa giao diện và triển khai 29 từ 86. Điều đó không có nghĩa là các đối tượng 88 có thể được thay đổi kích thước. Nó có nghĩa là giao diện là khác nhau vì nó chỉ cần tham số 21.Sự khác biệt trong giao diện này biện minh cho việc không lấy được 88 từ 86 như bài kiểm tra ở trên nên được khuyên.Trộn các tính năng với các lớp mixinMột trong những cách sử dụng của nhiều kế thừa trong Python là mở rộng một 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 pháp cho các lớp khác nhưng không được coi là một lớp cơ sở.mixin is a class that provides methods to other classes but are not considered a base class. Một 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 một lớp siêu. Họ thực hiện một hành vi độc đáo 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ư sáng tác nhưng chúng tạo ra một mối quan hệ mạnh mẽ hơn. Hãy nói rằng 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 bạn thành biểu diễn từ điển của đối tượng. Bạn có thể cung cấp một phương thức 53 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 53 dường như rất giống nhau.Đây có thể là một ứng cử viên tốt cho một mixin. Bạn bắt đầu bằng cách sửa đổi một chút lớp 51 từ ví dụ thành phần: 0Sự thay đổi là rất nhỏ. Bạn vừa thay đổi các thuộc tính 45 và 59 là nội bộ bằng cách thêm một dấu gạch dưới hàng đầu vào tên của chúng. Bạn sẽ thấy sớm tại sao bạn đang thực hiện thay đổi đó.Bây giờ, bạn thêm lớp 58: 1Lớp 58 phơi bày phương pháp 53 trả về biểu diễn của chính nó như một từ điển. Phương pháp này được thực hiện dưới dạng hiểu biết 61 cho biết, Tạo bản đồ từ điển 62 đến 63 cho mỗi mục trong 64 nếu 62 không phải là nội bộ.Như bạn đã thấy lúc đầu, tạo một lớp kế thừa một số thành viên từ 32 và một trong những thành viên đó là 30, về cơ bản là ánh xạ của tất cả các thuộc tính trong một đối tượng theo giá trị của chúng.Bạn lặp lại tất cả các mục trong 30 và lọc ra các mục có tên bắt đầu bằng dấu gạch dưới bằng 69. 70 Kiểm tra giá trị được chỉ định. Nếu giá trị là một 32, thì có vẻ như xem nó cũng có thành viên 53 và sử dụng nó để thể hiện đối tượng. Nếu không, nó trả về một đại diện chuỗi. Nếu giá trị không phải là 32, thì nó chỉ cần trả về giá trị.is an 32, then it looks to see if it also has a 53 member and uses it to represent the object. Otherwise, it returns a string representation. If the value is not an 32, then it simply returns the value.Bạn có thể sửa đổi lớp 51 để hỗ trợ mixin này: 2Tất cả bạn phải làm là thừa hưởng 58 để hỗ trợ chức năng. Sẽ rất tuyệt khi hỗ trợ chức năng tương tự trong lớp 58, do đó, thuộc tính 77 được thể hiện theo cùng một cách: 3Bạn áp dụng mixin cho lớp 58 để 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ó: 4Chương trình thực hiện một 79 chuyển đổi từ điển thành chuỗi JSON bằng cách sử dụng thụt vào để đầu ra trông tốt hơn.Sau đó, nó lặp lại thông qua tất cả các nhân viên, in biểu diễn từ điển được cung cấp bởi 53. Bạn có thể chạy chương trình để xem đầu ra của nó: 5Bạn đã tận dụng việc triển khai 58 trong cả hai lớp 51 và 58 ngay cả khi chúng không liên quan. Bởi vì 58 chỉ cung cấp hành vi, rất dễ sử dụng lại với các lớp khác mà không gây ra vấn đề.Sáng tác để mô hình "có một mối quan hệ"Mô hình sáng tác A có một mối quan hệ. Với thành phần, lớp 03 có một thể hiện của lớp 04 và có thể tận dụng việc thực hiện nó. Lớp 04 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 03.has a relationship. With composition, a
class 03 has an instance of class 04 and can leverage its implementation. The 04 class can be reused in other classes completely unrelated to the 03.Trong ví dụ thành phần ở trên, lớp 51 có đối tượng 58. 58 thực hiện tất cả các chức năng để xử lý các địa chỉ và nó có thể được sử dụng lại bởi các lớp khác.has an 58 object. 58 implements all the functionality to handle addresses, and it can be reused by other classes.Các lớp khác như 41 hoặc 93 có thể tái sử dụng 58 mà không liên quan đến 51. 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ý nhất quán trên toàn bộ ứng dụng.Mộ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 trong các thành phần mà chúng được tạo. Đ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 phương pháp nhà máy để 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 41, bạn sẽ nhận thấy rằng nó sử dụng 51 để xây dựng đối tượng 51 với các tham số phù hợp.Thiết kế này sẽ hoạt động, nhưng lý tưởng nhất, bạn sẽ có thể xây dựng một đối tượng 51 chỉ bằng cách chỉ định 48, ví dụ 01.Nhữ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 34: 6Đầu tiên, bạn thực hiện lớp nội bộ 03, sau đó cung cấp một biến bên trong 04 cho mô -đun. Bạn đang liên lạc 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 03. Thay vào đó, bạn cung cấp hai chức năng, 06 và 81, làm giao diện công cộng cho mô -đun. Đây là những gì các mô -đun khác nên sử dụng.Những gì bạn đang nói là 03 là một người độc thân, và chỉ nên có một đối tượng được tạo ra từ nó.Bây giờ, bạn có thể làm tương tự với mô -đun 21: 7Một lần nữa, bạn thực hiện nội bộ 10 và cung cấp một giao diện công cộng cho nó. Ứng dụng sẽ sử dụng giao diện công cộng để có được chính sách và tính toán bảng lương.Bây giờ bạn sẽ làm tương tự với mô -đun 72: 8Về cơ bản, bạn đang nói rằng chỉ nên có một 12, một 10 và một 03. Một lần nữa, mô hình thiết kế này được gọi là mẫu thiết kế Singleton, có ích cho các lớp mà chỉ nên có một, một trường hợp duy nhất.Bây giờ, bạn có thể làm việc trên mô -đun 70. Bạn cũng sẽ tạo ra một singleton trong số 16, nhưng bạn sẽ thực hiện một số thay đổi bổ sung: 9Trước tiên, bạn nhập các chức năng và lớp liên quan từ các mô -đun khác. 16 được thực hiện nội bộ và ở phía dưới, bạn tạo một thể hiện duy nhất. Trường hợp này là công khai và một phần của giao diện vì bạn sẽ muốn sử dụng nó trong ứng dụng.Bạn đã thay đổi thuộc tính 18 thành một từ điển trong đó khóa là nhân viên 48 và giá trị là thông tin của nhân viên. Bạn cũng đã phơi bày một phương thức 20 để trả về thông tin cho nhân viên được chỉ định 21.Tài sản 22 hiện sắp xếp các khóa để trả lại các nhân viên được sắp xếp theo 48 của họ. Bạn đã thay thế phương thức xây dựng các đối tượng 51 bằng các cuộc gọi đến trình khởi tạo 51 trực tiếp.Lớp 51 hiện được khởi tạo với 48 và sử dụng các chức năng công cộng được hiển thị 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: 0Bạn nhập các chức năng liên quan từ các mô -đun 21 và 34, cũng như lớp 30 và 51. Chương trình sạch hơn vì bạn tiếp xúc với giao diện cần thiết và đóng gói cách truy cập các đối tượng.Lưu ý rằng bây giờ bạn có thể tạo một đối tượng 51 trực tiếp chỉ bằng cách sử dụng 48 của nó. Bạn có thể chạy chương trình để xem đầu ra của nó: 1Chươ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 51 có thể được tạo từ 48 của nó và hiển thị biểu diễn từ điển của nó.Hãy xem xét kỹ hơn về lớp 51: 2Lớp 51 là một tổng hợp chứa nhiều đối tượng cung cấp chức năng khác nhau. Nó chứa một 58 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. 51 cũng chứa vai trò năng suất được cung cấp bởi mô -đun 34 và chính sách bảng lương được cung cấp bởi mô -đun 21. Hai đối tượng này cung cấp các triển khai được loại bỏ bởi lớp 51 để theo dõi công việc theo phương thức 88 và để tính toán bảng lương trong phương thức 47.Bạn đang sử dụng sáng tác theo hai cách khác nhau. Lớp 58 cung cấp dữ liệu bổ sung cho 51 trong đó các đối tượng vai trò và bảng lương cung cấp hành vi bổ sung.Tuy nhiên, mối quan hệ giữa 51 và các đối tượng đó được ghép nối một cách lỏng lẻo, cung cấp một số khả năng thú vị mà bạn sẽ thấy trong phần tiếp theo.Thành phần để thay đổi hành vi thời gian chạyKế thừa, trái ngược với sáng tác, là một mối quan hệ cặp đôi chặt chẽ. Với sự kế thừa, chỉ có một cách để thay đổi và tùy chỉnh hành vi. Ghi đè phương thức là cách duy nhất để tùy chỉnh hành vi của một lớp cơ sở. Điều này tạo ra các 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 ghép nối lỏng lẻo cho phép thiết kế linh hoạt và có thể được sử dụng để thay đổi hành vi trong thời gian chạy. Hãy tưởng tượng bạn cần hỗ trợ chính sách khuyết tật dài hạn (LTD) khi tính toán bảng lương. Chính sách tuyên bố rằng một nhân viên trên LTD nên được trả 60% tiền lương hàng tuần của họ với 40 giờ làm việc. Với một thiết kế kế thừa, đây có thể là một yêu cầu rất khó để hỗ trợ. Thêm nó vào ví dụ thành phần dễ dàng hơn rất nhiều. Hãy bắt đầu bằng cách thêm lớp chính sách: 3Lưu ý rằng 48 không kế thừa 06, nhưng thực hiện cùng một giao diện. Điều này là do việc triển khai hoàn toàn khác nhau, vì vậy chúng tôi không muốn kế thừa bất kỳ triển khai 06 nào. 48 khởi tạo 52 đến 68 và cung cấp một phương thức 54 nội bộ làm tăng ngoại lệ nếu 55 chưa được áp dụng. Sau đó, nó cung cấp một phương thức 56 để gán 52.Giao diện công cộng trước tiên kiểm tra xem 52 đã được áp dụng, và sau đó thực hiện chức năng theo chính sách cơ sở đó. Phương pháp 59 chỉ ủy quyền cho chính sách cơ sở và 47 sử dụng nó để tính toán 61 và sau đó trả lại 60%.Bây giờ bạn có thể thực hiện một thay đổi nhỏ cho lớp 51: 4Bạn đã thêm một phương thức 63 á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ó. Bây giờ bạn có thể sửa đổi chương trình để áp dụng chính sách cho đối tượng 51: 5Chương trình truy cập 65, được đặt tại Index 66, tạo đối tượng 48 và áp dụng chính sách cho nhân viên. Khi 47 được gọi, sự thay đổi được phản ánh. Bạn có thể chạy chương trình để đánh giá đầu ra: 6Số tiền kiểm tra cho nhân viên Kevin Bacon, nhân viên bán hàng, hiện có giá $ 1080 thay vì $ 1800. Đó là vì 48 đã được áp dụng cho mức lương.Như bạn có thể thấy, bạn đã có thể hỗ trợ các thay đổi chỉ bằng cách thêm một chính sách mới và sửa đổi một vài giao diện. Đâ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 thừa kế và thành phần trong PythonPython, như một ngôn ngữ lập trình định hướng đối tượng, hỗ trợ cả kế thừa và thành phần. Bạn thấy rằng sự kế thừa được sử dụng tốt nhất để mô hình hóa A là một mối quan hệ, trong khi các mô hình thành phần A có mối quan hệ.is a relationship, whereas composition models a has a relationship. Đôi khi, thật khó để thấy mối quan hệ giữa hai lớp nên là gì, nhưng bạn có thể làm theo các hướng dẫn này:
Sự kết luậnBạn đã khám phá sự kế thừa và sáng tác trong Python. Bạn đã học về loại mối quan hệ mà sự kế thừa và sáng tác tạo ra. Bạn cũng đã trải qua một loạt các bài tập để hiểu làm thế nào kế thừa và sáng tác được thực hiện trong Python.inheritance and composition in Python. You learned about the type of relationships that inheritance and composition create. You also went through a series of exercises to understand how inheritance and composition are implemented in Python. Trong bài viết này, bạn đã học được cách:
Đề xuất đọcDưới đây là một số cuốn sách và bài viết khám phá thêm thiết kế theo hướng đối tượng và có thể hữu ích để giúp bạn hiểu được việc sử dụng chính xác sự kế thừa và bố cục trong Python hoặc các ngôn ngữ khác:
Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem nó cùng với hướng dẫn bằng văn bản để làm sâu sắc thêm sự hiểu biết của bạn: Kế thừa và sáng tác: Hướng dẫn Python OOP This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Inheritance and Composition: A Python OOP Guide |