Bagaimana cara berpikir tentang pola desain dan praktik OOP berubah dalam bahasa yang dinamis dan diketik dengan lemah?

11

Sudah ada pertanyaan yang cukup membantu di sepanjang garis ini (" Pola Desain Non-OOP? "), Tetapi saya lebih ingin tahu tentang sudut pandang transisi untuk seseorang yang baru memulai dengan bahasa yang dinamis dan diketik dengan lemah.

Yaitu: katakanlah saya telah memprogram dalam C ++, C #, atau Java selama bertahun-tahun, dan menyerap banyak kebijaksanaan di sepanjang garis pola desain GoF, Pola Fowler tentang Arsitektur Aplikasi Perusahaan , prinsip SOLID , dll. Sekarang saya Saya mencoba-coba Ruby, Python, JavaScript, dll., dan bertanya-tanya bagaimana pengetahuan saya berlaku. Agaknya saya bisa melakukan terjemahan langsung dalam banyak kasus, tetapi hampir pasti itu tidak akan mengambil keuntungan penuh dari pengaturan baru saya. Mengetik bebek saja mengubah banyak pemikiran berbasis antarmuka saya.

Apa yang tetap sama? Perubahan apa? Apakah ada prinsip panduan seperti SOLID, atau pola kanonik (mungkin sama sekali baru) yang harus diketahui oleh pemula yang dinamis?

Domenik
sumber

Jawaban:

7

Apa yang tetap sama? Perubahan apa?

Polanya sama. Teknik bahasa berubah.

Apakah ada prinsip panduan seperti SOLID,

Iya. Memang, mereka tetap menjadi prinsip panduan. Tidak ada yang berubah.

atau pola kanonik (mungkin seluruhnya baru) yang harus diketahui oleh pemula yang dinamis?

Beberapa hal unik. Sebagian besar dampaknya adalah bahwa teknik implementasi berubah.

Sebuah pola - yah - sebuah pola . Bukan hukum. Bukan subrutin. Bukan makro. Itu hanya ide bagus yang diulang karena itu ide yang bagus.

Ide bagus tidak keluar dari gaya atau berubah secara dramatis.

Catatan lain. Python tidak "diketik dengan lemah". Ini lebih kuat daripada Java atau C ++ karena tidak ada operasi pemeran. [Ya, ada cara untuk memalsukan kelas yang terkait dengan objek, tapi itu bukan hal yang dilakukan kecuali untuk membuktikan titik legalistis yang rewel.]

Juga. Kebanyakan pola desain didasarkan pada berbagai cara untuk mengeksploitasi polimorfisme.

Lihatlah State atau Command atau Memento sebagai contoh. Mereka memiliki hierarki kelas untuk membuat status polimorfis, perintah atau kenang-kenangan perubahan negara. Tidak ada yang berubah secara signifikan ketika Anda melakukan ini dengan Python. Perubahan kecil termasuk relaksasi hirarki kelas yang tepat karena polimorfisme dalam Python tergantung pada metode umum bukan nenek moyang yang sama.

Juga, beberapa pola hanyalah upaya untuk mencapai ikatan yang terlambat. Sebagian besar pola yang terkait dengan Pabrik adalah upaya untuk memungkinkan perubahan mudah ke hierarki kelas tanpa mengkompilasi ulang setiap modul C ++ dalam aplikasi. Ini bukan optimasi yang menarik dalam bahasa yang dinamis. Namun, Pabrik sebagai cara untuk menyembunyikan detail implementasi masih memiliki nilai besar.

Beberapa pola merupakan upaya untuk menggerakkan kompiler dan tautan. Singleton , misalnya, ada untuk menciptakan global yang membingungkan tetapi setidaknya merangkum mereka. Kelas python singleton bukanlah prospek yang menyenangkan. Tetapi modul Python sudah merupakan lajang, jadi banyak dari kita hanya menggunakan modul dan menghindari mencoba mengacaukan dengan kelas Singleton .

S.Lott
sumber
Saya tidak akan mengatakan bahwa "tidak ada yang berubah" dengan SOLID. Bergantung pada bahasa dan model objeknya, Prinsip Terbuka-Tutup dan Prinsip Pergantian Liskov mungkin tidak ada artinya. (JavaScript dan Go keduanya terlintas dalam pikiran.)
Mason Wheeler
@Mason Wheeler. Open-Closed adalah bahasa yang tidak tergantung pada pengalaman saya. Anda harus memberikan beberapa contoh konkret tentang bagaimana desain buka-tutup "tidak berarti" dengan JavaScript atau Go. Substitusi Liskov, mungkin, tidak berlaku untuk JavaScript, tetapi pola penting - polimorfisme - tampaknya masih berlaku.
S.Lott
@ S.Lott: Pembaruan bagus di edit; mereka jauh lebih menarik daripada jawaban aslinya: P. Terima kasih telah memperbaiki kesalahan Python saya. Secara umum contoh-contoh pola spesifik dan bagaimana mereka mengikat ke dalam bahasa yang dinamis, polimorfisme, mengikat akhir, dll. Sempurna.
Domenic
@ S.Lott: Karena Open / Closed adalah tentang warisan, yang tidak dimiliki oleh bahasa-bahasa tersebut. (Juga, gagasan tentang objek yang "ditutup untuk modifikasi" tidak akan cocok dengan banyak coders Ruby ...)
Mason Wheeler
@Mason Wheeler: Terima kasih atas klarifikasi pada Open / Closed. Saya pikir pengecualian JavaScript itu penting, tetapi karena pertanyaannya sangat terbuka (mencantumkan JavaScript, Python dan Ruby, serta bahasa yang disebut ETC) Saya tidak yakin bagaimana menangani kasus khusus ini.
S.Lott
8

Peter Norvig menjawab pertanyaan ini pada tahun 1998, baca http://norvig.com/design-patterns/ppframe.htm untuk serangkaian hal terperinci yang ia perhatikan, dan http://c2.com/cgi/wiki?AreDesignPatternsMissingLanguageFeatures for diskusi lebih lanjut di sekitar titik.

Versi singkatnya adalah bahwa ketika bahasa Anda memiliki lebih banyak fitur, maka pola desain yang berulang cenderung menjadi lebih sederhana - sering kali tidak terlihat. Dia menemukan bahwa ini berlaku untuk sebagian besar pola desain yang telah diidentifikasi oleh GoF.

btilly
sumber
8

Pemrograman dalam bahasa berorientasi objek dinamis menggunakan banyak pola dan prinsip yang sama, tetapi ada beberapa perubahan dan perbedaan karena lingkungan:

Ganti Antarmuka dengan Mengetik Bebek - Di mana Geng Empat akan memberitahu Anda untuk menggunakan kelas dasar abstrak dengan fungsi virtual murni, dan Anda akan menggunakan antarmuka di Jawa, dalam bahasa yang dinamis, Anda hanya perlu pemahaman. Karena Anda dapat menggunakan objek apa saja di mana saja, dan itu akan berfungsi dengan baik jika mengimplementasikan metode yang sebenarnya disebut, Anda tidak perlu mendefinisikan antarmuka formal. Mungkin layak mendokumentasikan satu, sehingga jelas apa yang sebenarnya diperlukan.

Fungsi juga Obyek - Ada banyak pola yang memisahkan keputusan dari tindakan; Komando, Strategi, Rantai Tanggung Jawab, dll. Dalam bahasa dengan fungsi kelas satu, seringkali masuk akal untuk sekadar mengoper fungsi alih-alih membuat objek dengan .doIt()metode. Pola-pola ini berubah menjadi "menggunakan fungsi urutan yang lebih tinggi."

TERJUAL - Prinsip Segregasi Antarmuka mengambil manfaat terbesar di sini, karena tidak ada antarmuka. Anda tetap harus mempertimbangkan prinsipnya, tetapi Anda tidak dapat memasukkannya kembali ke dalam kode Anda. Hanya kewaspadaan pribadi yang akan melindungi Anda di sini. Di sisi atas, rasa sakit yang disebabkan oleh melanggar prinsip ini jauh berkurang di lingkungan dinamis umum.

"... di Partikelku sendiri ... Idiom!" - Setiap bahasa memiliki praktik baik dan praktik buruk, dan Anda harus mempelajarinya, dan mengikuti mereka, jika Anda menginginkan kode terbaik dalam bahasa tersebut. Pola iterator yang ditulis dengan sempurna dapat ditertawakan dalam bahasa dengan pemahaman daftar bawaan, misalnya.

Sean McMillan
sumber
3

Dalam pengalaman saya, beberapa Pola masih berguna dalam Python, dan bahkan lebih mudah diatur daripada dalam bahasa yang lebih statis. Beberapa Pola OTOH tidak diperlukan, atau bahkan disukai, seperti Pola Singleton. Gunakan variabel tingkat atau fungsi modul sebagai gantinya. Atau gunakan Pola Borg.

Alih-alih menyiapkan Pola Penciptaan itu sering kali cukup untuk melewati callable di sekitar yang menciptakan objek. Itu bisa berupa fungsi, objek dengan __call__metode atau bahkan kelas, karena tidak ada new()dalam Python, hanya doa dari kelas itu sendiri:

def make_da_thing(maker, other, stuff):
    da_thing = maker(other + 1, stuff + 2)
    # ... do sth
    return da_thing

def maker_func(x, y):
     return x * y

class MakerClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
...
a = make_da_thing(maker_func, 5, 8)
b = make_da_thing(MakerClass, 6, 7)

Pola Negara dan Strategi berbagi struktur yang sangat mirip dalam bahasa seperti C ++ dan Java. Kurang begitu dengan Python. Pola Strategi tetap kurang lebih sama, tetapi Pola Negara menjadi sebagian besar tidak perlu. Pola Negara dalam bahasa statis mensimulasikan perubahan kelas saat runtime. Dengan Python, Anda bisa melakukan hal itu: mengubah kelas objek saat runtime. Selama Anda melakukannya dengan cara yang terkontrol dan dienkapsulasi, Anda akan baik-baik saja:

class On(object):
    is_on = True
    def switch(self):
        self.__class__ = Off

class Off(object):
    is_on = False
    def switch(self):
        self.__class__ = On
...

my_switch = On()
assert my_switch.is_on
my_switch.switch()
assert not my_switch.is_on

Pola yang bergantung pada Pengiriman Jenis Statis tidak akan berfungsi, atau bekerja dengan sangat berbeda. Anda tidak harus menulis sebanyak kode pelat ketel, misalnya Pola Pengunjung: di Jawa dan C ++ Anda harus menulis metode penerimaan di setiap kelas yang dapat dikunjungi, sedangkan dengan Python Anda dapat mewarisi fungsi itu melalui kelas mixin, seperti Visitable:

class Visitable(object):
    def accept(self, visitor):
        visit = getattr(visitor, 'visit' + self.__class__.__name__)
        return visit(self)
...

class On(Visitable):
    ''' exactly like above '''

class Off(Visitable):
    ''' exactly like above '''

class SwitchStatePrinter(object): # Visitor
    def visitOn(self, switch):
         print 'the switch is on'
    def visitOff(self, switch):
         print 'the switch is off'

class SwitchAllOff(object): # Visitor
    def visitOn(self, switch):
         switch.switch()
    def visitOff(self, switch):
         pass
...
print_state = SwitchStatePrinter()
turn_em_off = SwitchAllOff()
for each in my_switches:
    each.accept(print_state)
    each.accept(turn_em_off)

Banyak situasi yang membutuhkan penerapan Pola dalam Bahasa Statis yang tidak banyak menggunakan Python. Banyak hal yang dapat diselesaikan dengan teknik lain, seperti fungsi tingkat tinggi (dekorator, pabrik fungsi) atau kelas meta.

pembuat pil
sumber
Saya menyadari sekarang bahwa jawaban Anda paling banyak mencakup pertanyaan yang baru saja saya tanyakan: Apakah menimpa __class__untuk mengimplementasikan pabrik dengan Python adalah ide yang bagus?
rds