Mengingat bahwa Python memungkinkan pewarisan berganda, seperti apa pewarisan idiomatik dalam Python?
Dalam bahasa dengan pewarisan tunggal, seperti Java, pewarisan akan digunakan ketika Anda bisa mengatakan bahwa satu objek "adalah-a" dari objek lain dan Anda ingin berbagi kode antara objek (dari objek induk ke objek anak). Misalnya, Anda dapat mengatakan bahwa Dog
ini adalah Animal
:
public class Animal {...}
public class Dog extends Animal {...}
Tetapi karena Python mendukung banyak pewarisan, kita dapat membuat objek dengan menyusun banyak objek lain bersamaan. Perhatikan contoh di bawah ini:
class UserService(object):
def validate_credentials(self, username, password):
# validate the user credentials are correct
pass
class LoggingService(object):
def log_error(self, error):
# log an error
pass
class User(UserService, LoggingService):
def __init__(self, username, password):
self.username = username
self.password = password
def authenticate(self):
if not super().validate_credentials(self.username, self.password):
super().log_error('Invalid credentials supplied')
return False
return True
Apakah ini merupakan pewarisan berganda dari Python yang dapat diterima atau digunakan dengan baik? Alih-alih mengatakan warisan adalah ketika satu objek "adalah-a" dari objek lain, kita membuat User
model yang terdiri dari UserService
dan LoggingService
.
Semua logika untuk operasi basis data atau jaringan dapat disimpan terpisah dari User
model dengan meletakkannya di UserService
objek dan menyimpan semua logika untuk masuk LoggingService
.
Saya melihat beberapa masalah dengan pendekatan ini adalah:
- Apakah ini menciptakan objek Tuhan? Karena
User
mewarisi dari, atau terdiri dari,UserService
danLoggingService
apakah itu benar-benar mengikuti prinsip tanggung jawab tunggal? - Untuk mengakses metode pada objek induk / objek berikutnya (misalnya,
UserService.validate_credentials
kita harus menggunakansuper
. Ini membuatnya sedikit lebih sulit untuk melihat objek mana yang akan menangani metode ini dan tidak sejelas, katakanlah , InstantiatingUserService
dan melakukan sesuatu sepertiself.user_service.validate_credentials
Apa yang akan menjadi cara Pythonic untuk mengimplementasikan kode di atas?
User
objek memiliki antarmuka mereka tidak hanya anggota yang ditentukan diUser
kelas, tetapi juga yang didefinisikan dalamUserService
danLoggingService
. Ini bukan hubungan "has-a", karena antarmuka publik disalin (meskipun tidak melalui penyalinan langsung, tetapi lebih oleh pencarian tidak langsung ke antarmuka superclasses ').Selain fakta bahwa itu memungkinkan beberapa superclasses, pewarisan Python tidak jauh berbeda dengan Java, yaitu anggota subkelas juga anggota dari masing-masing supertipe mereka [1]. Fakta bahwa Python menggunakan pengetikan bebek juga tidak ada bedanya: subclass Anda memiliki semua anggota superclasses, sehingga dapat digunakan oleh kode apa pun yang dapat menggunakan subclass tersebut. Fakta bahwa pewarisan berganda diterapkan secara efektif dengan menggunakan komposisi adalah herring merah: bahwa penyalinan otomatis properti dari satu kelas ke kelas lain adalah masalahnya, dan tidak masalah apakah itu menggunakan komposisi atau hanya menebak secara ajaib bagaimana anggotanya seharusnya untuk bekerja: memiliki mereka salah.
Ya, ini melanggar tanggung jawab tunggal, karena Anda memberi objek Anda kemampuan untuk melakukan tindakan yang bukan bagian logis dari apa yang mereka dirancang untuk dilakukan. Ya, itu menciptakan objek "dewa", yang pada dasarnya adalah cara lain untuk mengatakan hal yang sama.
Saat merancang sistem berorientasi objek dengan Python, pepatah yang sama yang diberitakan oleh buku desain Java juga berlaku: lebih suka komposisi daripada warisan. Hal yang sama berlaku untuk (kebanyakan [2]) sistem lain dengan banyak pewarisan.
[1]: Anda dapat menyebut bahwa hubungan "is-a", meskipun saya pribadi tidak suka istilah itu karena ini menyarankan gagasan pemodelan dunia nyata, dan pemodelan berorientasi objek tidak sama dengan dunia nyata.
[2]: Saya tidak begitu yakin tentang C ++. C ++ mendukung "warisan pribadi" yang pada dasarnya adalah komposisi tanpa perlu menentukan nama bidang ketika Anda ingin menggunakan anggota publik kelas yang diwariskan. Sama sekali tidak memengaruhi antarmuka publik kelas. Saya tidak suka menggunakannya, tapi saya tidak bisa melihat alasan bagus untuk tidak melakukannya.
sumber