Bisakah Anda menerapkan pemrograman "berorientasi objek" tanpa kata kunci kelas?

29

Katakanlah kami ingin memberikan abstraksi "akun" di bank. Inilah satu pendekatan, menggunakan functionobjek dalam Python:

def account():
    """Return a dispatch dictionary representing a bank account.

    >>> a = account()
    >>> a['deposit'](100)
    100
    >>> a['withdraw'](90)
    10
    >>> a['withdraw'](90)
    'Insufficient funds'
    >>> a['balance']
    10
    """
    def withdraw(amount):
        if amount > dispatch['balance']:
            return 'Insufficient funds'
        dispatch['balance'] -= amount
        return dispatch['balance']
    def deposit(amount):
        dispatch['balance'] += amount
        return dispatch['balance']
    dispatch = {'balance': 0,
                'withdraw': withdraw,
                'deposit': deposit}
    return dispatch

Berikut pendekatan lain menggunakan abstraksi tipe (yaitu, classkata kunci dengan Python):

class Account(object):
    """A bank account has a balance and an account holder.

    >>> a = Account('John')
    >>> a.deposit(100)
    100
    >>> a.withdraw(90)
    10
    >>> a.withdraw(90)
    'Insufficient funds'
    >>> a.balance
    10
    """



    def __init__(self, account_holder):
        self.balance = 0
        self.holder = account_holder

    def deposit(self, amount):
        """Add amount to balance."""
        self.balance = self.balance + amount
        return self.balance

    def withdraw(self, amount):
        """Subtract amount from balance if funds are available."""
        if amount > self.balance:
            return 'Insufficient funds'
        self.balance = self.balance - amount
        return self.balance

Guru saya memulai topik "Pemrograman berorientasi objek" dengan memperkenalkan classkata kunci, dan menunjukkan kepada kami poin-poin berikut:

Pemrograman berorientasi objek

Metode untuk mengatur program modular:

  • Hambatan abstraksi
  • Pesan lewat
  • Menyatukan informasi dan perilaku terkait

Apakah Anda pikir pendekatan pertama akan cukup untuk memenuhi definisi di atas? Jika ya, mengapa kita perlu classkata kunci untuk melakukan pemrograman berorientasi objek?

pertukaran berlebihan
sumber
2
Senang kamu setuju. =) Meskipun saya tidak tahu Python cukup baik untuk memberikan jawaban yang menyeluruh, Anda mungkin tertarik untuk mengetahui bahwa dalam Javascript cara khas melakukan OOP mirip dengan "objek fungsi" yang Anda jelaskan (meskipun kami juga memiliki warisan prototipe yang memungkinkan objek untuk "berbagi" metode alih-alih memiliki salinan terpisah dari setiap metode pada setiap objek; Saya menganggap Python classmelakukan optimasi yang sama).
Ixrec
Jika Anda menginginkan jawaban terperinci, Anda harus mengajukan pertanyaan lain atau bergabung dengan ruang obrolan, tetapi jawaban singkatnya adalah (jika Anda benar-benar mengabaikan warisan prototipe, array, dll.) Itu pada dasarnya benar; sebagian besar objek JS tidak lain hanyalah kamus dari kunci string untuk nilai arbitrer. foo.bar()biasanya identik dengan foo['bar'](), dan pada kesempatan langka sintaks yang terakhir sebenarnya berguna.
Ixrec
8
Ini adalah pertanyaan yang sangat penting dalam perjalanan Anda menuju pemahaman mendasar tentang OOP. Jika Anda tertarik, Anda dapat membaca posting blog saya di mana saya membuat sistem objek sederhana dalam JavaScript tanpa bergantung pada bagian OOP bahasa apa pun. Contoh pertama Anda memiliki kekurangan penting: Di mana Anda akan menulis object['method'](args), objek Python benar-benar melakukan hal yang setara object['method'](object, args). Ini menjadi relevan ketika kelas dasar memanggil metode dalam kelas anak, misalnya dalam Pola Strategi.
amon
13
Seperti yang telah dicatat orang lain, ini adalah pertanyaan perseptif tentang OOP. Namun saya akan mengambil kesempatan ini untuk mencatat bahwa ini sama sekali bukan bank nyata yang mewakili rekening bank. Bank tidak memiliki objek "akun" yang dapat berubah yang berubah saat Anda mendebit dan mengkreditnya; mereka memiliki daftar transaksi yang hanya dapat ditulis, dan kemudian menghitung saldo dari daftar transaksi. Sebagai latihan yang baik, cobalah menerapkan mekanisme itu dalam berbagai bahasa.
Eric Lippert

Jawaban:

66

Selamat! Anda menemukan kembali fakta terkenal bahwa orientasi objek dapat dilakukan tanpa dukungan bahasa pemrograman tertentu. Pada dasarnya ini adalah cara yang sama dengan objek yang diperkenalkan dalam Skema dalam buku teks klasik ini . Perhatikan bahwa Skema tidak memiliki classkata kunci atau sejenisnya, dan objek dapat dibuat tanpa kelas genap.

Namun, paradigma berorientasi objek sangat sukses sehingga banyak bahasa - dan Python tidak terkecuali - menyediakan dukungan bawaan untuknya. Ini hanya untuk memudahkan pengembang untuk menggunakan paradigma dan menyediakan bentuk standar orientasi objek untuk bahasa itu. Ini pada dasarnya adalah alasan yang sama mengapa banyak bahasa menyediakan forloop, meskipun itu bisa ditiru menggunakan whileloop hanya dengan satu atau dua baris kode tambahan - cukup mudah digunakan .

Doc Brown
sumber
"untuk memberikan bentuk standar orientasi objek untuk bahasa itu" Apakah saya mendengar kritik terhadap JavaScript di sana? ;)
jpmc26
1
@ jpmc26: tidak sengaja. Dan tampaknya ada beberapa standar yang diterima secara luas bagaimana objek dibuat dalam JavaScript.
Doc Brown
@ overexchange: Anda punya pertanyaan untuk ditanyakan?
Doc Brown
1
@exexchange: Ya, apa yang dimaksud dengan OOP masih bisa diperdebatkan, ada berbagai aliran pemikiran, tetapi definisi SICP cukup mirip dengan 3 poin utama dalam pertanyaan Anda. Ini jelas tentang membangun abstraksi, tetapi jangan lupa poin 2 dan 3. Ya, konsep OOP menyertakan "perubahan negara", tetapi juga memungkinkan konsep "objek abadi" (seperti kelas string di Jawa atau C #, Python memiliki beberapa tipe data yang dapat berubah dan juga tidak dapat diubah). Dan contoh pertama Anda dalam pertanyaan Anda menegaskan definisi itu serta contoh kedua Anda.
Doc Brown
2
@overexchange: ini kembali ke definisi Alain Kay tentang orientasi objek (penemu bahasa bicara kecil). Anda akan menemukan jawaban yang komprehensif dalam stackoverflow.com/questions/2347973/... mantan artikel SO ini. IMHO "pesan yang lewat di antara objek" dalam arti SICP hanya berarti tidak mengakses data bagian dalam objek secara langsung, hanya melalui "protokol komunikasi yang ditentukan". Dalam bahasa OO seperti Python, ini bisa berarti "memanggil metode objek".
Doc Brown
13

Saya setuju bahwa definisi pertama memenuhi tiga poin yang dibuat oleh guru Anda. Saya tidak berpikir kita perlu kata kunci kelas untuk apa pun. Di bawah selimut, apa lagi yang merupakan objek tetapi struktur data dengan berbagai jenis data dan fungsi untuk bekerja dengan data? Tentu saja, fungsinya adalah data juga ..

Saya akan melangkah lebih jauh dan mengatakan bahwa melakukan pemrograman berorientasi objek tidak terlalu tergantung pada kata kunci yang disediakan bahasa Anda, Anda dapat melakukan pemrograman berorientasi objek dalam C jika Anda menginginkannya! Bahkan, kernel linux menggunakan teknik seperti itu.

Apa yang dapat Anda simpulkan dari kata kunci kelas di sini adalah, bahwa bahasa tersebut memberikan dukungan untuk konstruksi semacam ini di luar kotak, dan Anda tidak perlu melalui semua rintangan untuk menerapkan kembali fungsi itu sendiri (yang merupakan tugas yang cukup menyenangkan di diri!). Belum lagi semua gula sintaksis yang mungkin Anda dapatkan juga.

Zavior
sumber
bagaimana dengan warisan? Apakah kita penting tentang subtipe / supertipe secara langsung? Pendekatan pertamaku mungkin tidak menghibur ini !!
overexchange
5
Warisan sama sekali tidak diperlukan untuk OOP. Anda bisa menerapkan warisan dalam contoh pertama Anda juga. Itu tidak terlalu "bersih" tetapi mungkin semua sama.
Zavior
3
@Zavior komentar itu membuat saya memikirkan VB6. Berorientasi objek tanpa warisan memang membuat kode kurang bersih, untuk membuatnya lebih ringan.
RubberDuck
1
@exexchange Ketika Anda memikirkannya, warisan adalah tentang berbagi kode / perilaku umum antar kelas. Tidak ada yang menghentikan Anda mengulangi semua kode itu sepanjang waktu. Akan sangat mengerikan untuk mempertahankannya. Ada alasan mengapa warisan ada :)
Zavior
1
@Zavior Dalam bentuknya yang paling dasar "subclassing" adalah abstraksi yang mengatakan "sebelum Anda mengembalikan fungsi pengiriman-dan-data-pesanan tingkat tinggi yang saya definisikan di sini (yang akan kita anggap sebagai" kelas "ha ha ha), instantiate fungsi 'superclass' pengiriman dan data yang dirujuk oleh ThisParentFoo ". Benar-benar hanya itu. Ketika sampai pada pewarisan berganda yang naif, sebenarnya masih tetap seperti itu, tetapi dengan peringatan bahwa Anda memperkenalkan "masalah intan", itulah sebabnya mengapa pewarisan berganda menyebalkan.
zxq9
9

Tentu saja Anda bisa!

Bahasa pemrograman mandiri adalah bahasa berorientasi objek berbasis prototipe dinamis di mana semuanya adalah objek dan tidak ada rasa kelas atau apa pun. Ini terfokus pada gagasan objek prototipe dan gagasan kloning mereka alih-alih memiliki kelas sebagai template tentang cara membuat objek.

Anda harus memeriksa http://www.selflanguage.org/ untuk informasi lebih lanjut. Saya pikir ini sangat menarik dan jika Anda suka OOP itu ide yang baik untuk memeriksa sesuatu yang tidak umum.

DraQ
sumber
0

Tidak selalu: itu tergantung pada bahasa. Anda telah menunjukkan kemampuan untuk melakukan ini dengan Python tetapi (jika pertanyaan Anda dimaksudkan sebagai agnostik bahasa meskipun menggunakan tag Python) tidak semua bahasa dapat melakukan ini. Java, misalnya, kebanyakan tidak bisa. Mengabaikan kelas yang berisi main, tidak ada cara untuk mendefinisikan metode / bidang sembarang pada objek yang didefinisikan dalam utama tanpa kata kunci kelas. Meskipun kelas anonim memang ada, mereka memerlukan antarmuka dan mereka tidak dapat memiliki anggota publik kecuali yang ditentukan dalam antarmuka. Meskipun dimungkinkan untuk mendefinisikan antarmuka khusus lalu membuat kelas anonim untuk mereka, ini secara efektif sama (tapi kurang nyaman) daripada hanya menggunakan kelas.

Doc Brown memiliki jawaban yang bagus tetapi yang ingin saya sampaikan adalah bahwa saya yakin setidaknya ada satu bahasa yang tidak memungkinkan solusi Anda sama sekali.

SkySpiral7
sumber
Sebagai seorang pemula, untuk mempelajari konsep "pemrograman berorientasi objek", ya saya mencoba untuk menjadi agnostik bahasa. Saya pikir "Doc Brown" telah memberikan jawaban pada baris yang sama, dia mengatakan kepada saya membaca sicp text-chap3, yang tidak ada hubungannya dengan sintaks bahasa apa pun.
overexchange
Saya berharap saya akan menyebutkan nama bahasa yang benar-benar mengharuskan menggunakan kelas untuk memvalidasi jawaban saya. Tapi saya hanya tahu beberapa bahasa dan sayangnya Java memungkinkan pekerjaan di sekitar. C ++ memiliki struct dan Javascript datar memungkinkan apa yang Anda peragakan. Saya menduga Smalltalk dan Eiffel mungkin memerlukan kelas karena saya mendengar mereka terstruktur dengan ketat.
SkySpiral7
Sebagai Doc Brown, Jika saya belajar oop menggunakan skema, saya tidak akan menanyakan pertanyaan ini. Sayangnya, versi SICP tentu saja yang saya pelajari menggunakan python.
overexchange
1
Setiap program Java yang valid harus mengandung classkata kunci sehingga tidak terlalu mengejutkan. Tetapi Anda benar-benar dapat menerapkan sistem objek Anda sendiri di atas sistem objek Java, meskipun saya tidak tahu mengapa Anda ingin melakukan hal seperti itu.
Brian Gordon
1. Java benar-benar istimewa dalam hal ini, karena Java telah membuang semua kata kunci lain yang mungkin digunakan untuk membuat struktur data khusus. Hampir semua bahasa lain yang saya tahu memiliki catatan atau penutupan. 2. Bahkan di java, Anda dapat memprogram pada memori yang dibangun dari array. Dan Anda dapat menerapkan orientasi objek di dalamnya, menggunakan classkata kunci hanya karena bahasa mengharuskan Anda untuk menempatkan fungsi Anda di kelas. Tentu saja, ini sangat teoretis, tetapi bahkan di Jawa Anda dapat melakukan Orientasi Objek tanpa kelas bawaan!
cmaster
0

Definisi guru Anda benar-benar kehilangan poin terpenting dari pemrograman berorientasi objek, satu hal yang membuatnya berguna dan unik. "Pesan yang lewat" adalah omong kosong yang diimpikan oleh orang-orang Smalltalk, dan ini merupakan kegagalan di mana-mana hal itu telah dicoba. Kekuatan sebenarnya dari OOP adalah sesuatu yang dikenal sebagai substitusi Liskov , dan walaupun konsepnya cukup sederhana untuk dijelaskan dan dipahami, implementasi yang mendasarinya cukup kompleks sehingga pada dasarnya tidak mungkin dilakukan dengan benar tanpa dukungan tingkat bahasa.

Gagasan substitusi Liskov adalah bahwa di mana pun kode Anda mengharapkan variabel dari jenis tertentu, ia harus dapat menerima jenis apa pun yang berasal dari jenis itu dan tetap berfungsi dengan benar tanpa harus memiliki pengetahuan tentang detail dari jenis yang diturunkan.

Misalnya, kerangka kerja GUI menggunakan substitusi Liskov di semua tempat. Mereka cenderung memiliki Controlkelas dasar yang dapat mewakili "kontrol apa saja", yang mendefinisikan antarmuka yang tahu tentang tindakan dasar seperti menggambar, mengubah ukuran, dan menanggapi input pengguna. Jika Anda mengklik kontrol, kerangka kerja UI akan memanggil Clickmetode pada kontrol tanpa harus peduli tentang kontrol apa itu, dan kemudian biarkan kontrol menangani klik dengan cara yang sesuai untuk kelasnya sendiri. Sebuah Buttonkontrol harus melakukan sesuatu yang sama sekali berbeda ketika diklik dari TextBoxkontrol, untuk memberikan hanya satu contoh.

Jadi ya, Anda bisa membuat sesuatu yang mirip dengan objek menggunakan trik fungsi bersarang yang dijelaskan di atas, tetapi karena Anda tidak bisa mendapatkan pewarisan dan substitusi Liskov dengan cara itu, itu adalah pengganti yang sangat terbatas untuk OOP sejati.

Mason Wheeler
sumber
Dalam bahasa C, tidak bisakah saya mengatakan 'struct parent {}' dan kemudian 'struct child {struct parent * ptr;}'? Apakah ini bukan warisan dalam sintaksis bahasa non-oop?
overexchange
@ overexchange: Itu adalah upaya non-OO untuk memalsukannya, tetapi kompiler tidak akan membiarkan Anda mengganti yang lain. (Anda tidak dapat meneruskan child*ke fungsi yang mengambil parent*sebagai argumen, setidaknya bukan tanpa typecast.) Dan lebih buruk lagi, struct C tidak dapat memiliki metode terikat padanya, dan tidak ada dukungan untuk metode virtual , yang apa yang membuat keajaiban substitusi Liskov bekerja, jadi Anda harus membuat VMT dengan tangan, yang merupakan proses rumit yang mudah dikacaukan.
Mason Wheeler
1
Kernel Linux menggunakan emulasi beberapa teknik OO, yang semuanya harus dikodekan secara manual tanpa dukungan bahasa. Hal ini menyebabkan banyak peluang untuk bug, yang, sebagai Linux, diimbangi oleh aplikasi liberal Hukum Linus. Ya, itu mungkin dilakukan - Turing kesetaraan membuktikan ini - tetapi poin saya bahwa sangat sulit untuk mendapatkan yang benar tanpa dukungan bahasa masih berlaku. Juga, mengapa semua pertanyaan ini tentang C ketika pertanyaannya adalah tentang Python? Di C itu tidak mungkin untuk melakukan trik fungsi bersarang di tempat pertama.
Mason Wheeler
1
@ overexchange Sejak kapan Java menjadi "surga programmer"?
Brandin
1
Pesan lewat bukan merupakan kegagalan di Smalltalk, Erlang, atau bahkan sistem OOP gaya Jawa di mana "pesan" berarti sesuatu yang berbeda dari "panggilan fungsi" (sinyal & slot Qt dengan antrian threads VS pemasaran lama Jawa menggunakan istilah "pesan" ketika itu berarti "panggilan metode"). Pesan! = Panggilan fungsi. Olahpesan asli tidak hanya berhasil, tampaknya menjadi satu-satunya cara yang kita tahu untuk menulis sistem bersamaan dan kuat secara besar-besaran. Ini ortogonal untuk menerapkan OOP gaya Java tanpa kata kunci 'kelas'. Itu bisa dilakukan. Itu tidak selalu bermanfaat. Pesan tidak penting.
zxq9
-1

Jawaban Singkat Cepat

Ya, Pemrogram dapat menerapkan Pemrograman Berorientasi Objek tanpa "Kelas".

Jawaban Deskriptif Ekstensif Panjang Membosankan

Ada beberapa variasi "Orientasi Objek", kata Altought, konsep pertama yang muncul di benak banyak programmer adalah "Kelas".

Ya, Pemrogram dapat menerapkan Pemrograman Berorientasi Objek tanpa "Kelas", tetapi, terbatas pada fitur dan batasan dari setiap bahasa pemrograman.

Posting Anda ditandai sebagai Python , oleh karena itu, judul pertanyaan Anda mungkin lebih seperti "Bagaimana menerapkan Pemrograman Berorientasi Objek tanpa Kelas di Python".

Saat ini saya menggunakan frase "Object and Class Oriented Programming", untuk mengidentifikasi dari variasi lain seperti Javascript "Prototyping", atau Visual Basic "Based", atau emulasi dalam "Pure C" menggunakan "functors".

umlcat
sumber