Prinsip dan nama metode OOP

22
class Boxer:

    def punch(self, punching_bag, strength):
        punching_bag.punch(strength)


class PunchingBag:

    def punch(self, strength):
        print "Punching bag punched with strength", strength

boxer = Boxer()
punching_bag = PunchingBag()

boxer.punch(punching_bag, 2)

Tidak diragukan lagi itu punchadalah nama metode yang bagus untuk petinju. Tapi apakah nama punchjuga bagus untuk metode meninju tas? Dalam kedua kasus yang saya maksud pukulan sebagai perintah (yaitu melakukan pukulan).

iklim
sumber

Jawaban:

23

Aturan praktis yang baik adalah bahwa nama metode harus berupa kata kerja atau predikat sedemikian rupa sehingga objek yang Anda panggil ( selfdalam konvensi Python standar, thisdalam sebagian besar bahasa lain) menjadi subjek.

Dengan aturan ini, file.closeagak salah, kecuali Anda pergi dengan model mental bahwa file menutup sendiri, atau bahwa fileobjek tidak mewakili file itu sendiri, melainkan menangani file atau semacam objek proxy.

Namun, tas tinju tidak pernah meninju dirinya sendiri, jadi punchingBag.punch()itu salah. be_punched()secara teknis benar, tetapi jelek. receive_punch()mungkin bekerja, atau handle_punch(). Pendekatan lain, cukup populer di JavaScript, adalah untuk memperlakukan pemanggilan metode seperti peristiwa, dan konvensi yang ada untuk pergi dengan nama acara, diawali dengan 'on', sehingga akan menjadi on_punched()atau on_hit(). Atau, Anda bisa mengadopsi konvensi yang partisip masa lalu menunjukkan suara pasif, dan dengan konvensi itu, nama metode akan adil punched().

Aspek lain yang perlu dipertimbangkan adalah apakah karung tinju benar-benar tahu apa yang menabraknya: apakah membuat perbedaan apakah Anda meninju, memukulnya dengan tongkat, atau menabraknya dengan truk? Jika demikian, apa bedanya? Bisakah Anda merebus perbedaan menjadi argumen, atau apakah Anda memerlukan metode berbeda untuk berbagai jenis hukuman yang diterima? Metode tunggal dengan parameter generik mungkin merupakan solusi yang paling elegan, karena menjaga derajat kopling tetap rendah, dan metode seperti itu tidak boleh disebut punched()atau handle_punch(), melainkan sesuatu yang lebih umum seperti receive_hit(). Dengan metode seperti itu, Anda dapat menerapkan semua jenis aktor yang bisa mengenai tas tinju, tanpa mengubah tas tinju itu sendiri.

tammmer
sumber
4
@ Art: ya dan tidak. File dapat (secara konseptual berbicara) menutup diri ketika ditanya; array dapat mengurutkan sendiri; tetapi meninju tas tidak meninju diri mereka sendiri.
tdammers
2
Oke, jika tas tinju kita mengenai dinding dengan kecepatan gila, apakah itu dinding yang meninju itu, atau apakah itu tinju yang mengalami pukulan pada dirinya sendiri dan dengan sendirinya?
1
@tdammers: Saran Anda untuk menggeneralisasi juga dapat mengarah ke antarmuka yang disebut Hitable.
Jens Piegsa
2
@ Artur: Saya pikir ini adalah di mana asumsi OOP bahwa setiap kalimat memiliki subjek alami, dan bahwa ide ini berlaku untuk pemrograman, rusak.
Pelaku
1
Jadi pertanyaan utamanya adalah. Jika file dapat menutup sendiri, array dapat mengurutkan sendiri, dll., Mengapa meninju tas tidak dapat meninju diri mereka sendiri? Apakah ada perbedaan nyata atau hanya dalam kasus pertama, kita terbiasa dan dalam kedua, kita tidak?
iklim
6

Saya pikir ini adalah masalah konseptual (bagaimana kita berpikir tentang dunia). Tidak apa-apa untuk mengatakan:

  • Lihat, pintunya tertutup. door.close()
  • Wow, kertasnya terlipat sendiri. paper.fold()
  • Apa apaan?! File di meja baru saja ditutup, tidak ada orang di sekitar. file.close()

Sungguh aneh untuk mengatakan:

  • Tas tinju di gym baru saja meninju dirinya sendiri. bag.punch()

Pertama-tama perlu memiliki sesuatu untuk meninju dirinya sendiri (misalnya lengan). Anda mungkin akan mengatakan:

  • Tas tinju sudah mulai bergerak sendiri seperti seseorang akan meninju. punching_bag.move()

Tidak apa-apa untuk objek terprogram untuk melakukan hal-hal yang biasanya orang lain lakukan / dengan mereka (di "dunia nyata"). Tapi saya kira itu harus selalu masuk akal setidaknya bahwa hal itu melakukannya untuk / dengan dirinya sendiri . Anda harus bisa membayangkannya dengan mudah tanpa menjadi kabur (seperti dalam kasus punching_bag).

iklim
sumber
2

Ini masalah selera, saya pikir. Punching bag's punch()metode setidaknya konsisten dengan file.close()atau frame.move()dalam arti mengalami tindakan pada dirinya sendiri. Pertanyaan yang lebih besar adalah, mengapa Boxerada punch(something)metode sama sekali?


sumber
Saya suka poin Anda tentang file.close (). Itu adalah sesuatu yang saya maksudkan. Mungkin petinju memiliki metode pukulan karena ada juga pelatih yang melatih petinju. Sebenarnya, saya hanya mencoba memberikan beberapa contoh tindakan (pesan) yang melewati beberapa objek dengan yang terakhir adalah "objek aksi". Saya punya sedikit masalah dengan list.append (4), account.deposit (50), file.close (), paper.fold () vs boxer.punch (), dog.bark (), logger.log () dll .
iklim
Saat melewati beberapa objek, ada 2 kasus: Anda menggunakan konteks terikat (mandiri), dan Anda tidak. Jika Anda melakukannya, metode Anda seharusnya Coach.sayPunchToBoxer(), Boxer.punchNearestBag()dan Bag.punch(). Kalau tidak, Anda harus menebak apa yang akan terjadi setiap kali Anda menelepon Coach.punch(). Aturan umum adalah: jika objek yang mengalami tindakan tidak ditentukan dalam nama metode, maka penerima adalah objek itu.
Baiklah, saya pikir ini juga baik-baik saja: coach.say_punch (petinju, punching_bag), boxer.punch (punching_bag). penerima yaitu tidak dalam nama metode tetapi dalam parameter.
iklim
1
Tentu, maksud saya penerima tindakan harus dapat ditebak dari pernyataan panggilan.
2

Anda memiliki dua pesan berbeda: satu untuk memerintahkan objek untuk ditinju dan satu untuk memberi tahu objek bahwa benda itu dilubangi. Pertimbangkan bahwa objek Boxer mungkin perlu merespons keduanya . Berbeda . Itu alasan yang sangat bagus untuk memberi mereka nama yang berbeda.

Kecenderungan saya adalah mempertahankan punch(boxer, object, strength)dan mengganti nama metode yang sebaliknya punched. Anda bisa memanggilnya handle_punchatau sesuatu seperti itu, tetapi kemudian masih ambigu apakah itu untuk menangani perintah pukulan atau pemberitahuan bahwa itu dipukul.

pengguna2313838
sumber
Poin bagus tentang Boxer yang membutuhkan pukulan dan sesuatu seperti handle_punch (akan defenddalam kasus khusus ini). Tapi karung tinju tidak akan menjadi dua arah seperti itu. Dan sudah ada file ini.close () ...
clime
defendadalah sebuah perintah. Ini adalah salah satu tindakan yang mungkin dilakukan oleh suatu objek sebagai respons punched, tetapi Anda tidak ingin objek lain memanggil defendsecara langsung.
user2313838
2

Pendekatan Anda pada akhirnya akan mengarah pada kode yang sangat berpasangan.

Untuk meringkas Eric Lippert idealnya di sini Anda ingin petinju dapat meninju banyak hal. Memiliki karung tinju sebagai tanda tangan dari fungsi petinju menyiratkan bahwa petinju dibuat dengan pengetahuan langsung tentang Semua (yang dapat ditinju). Ditambah memberi pukulan dan menerima pukulan adalah dua hal yang SANGAT berbeda, sehingga mereka tidak boleh menggunakan nama yang sama.

Saya lebih suka memodelkan ini sebagai Boxer yang menciptakan pukulan (objek lain yang berisi kekuatan atribut, jangkauan, arah dll).

Kemudian memiliki karung tinju dengan metode seperti onPunch yang menerima objek pukulan ini dapat menghitung efek dari pukulan itu sendiri.

Mengingat hal ini nama banyak hal penting. Itu harus sesuai dengan model mental yang Anda miliki tentang situasi tersebut. Jika Anda menemukan diri Anda mencoba menjelaskan bagaimana sesuatu dapat terjadi yang tidak masuk akal pada pandangan pertama, atau jika Anda memiliki waktu yang paling sulit untuk menamai sesuatu, mungkin model Anda salah dan perlu diubah.

Sulit untuk mengubah model setelah Anda mulai, orang umumnya cenderung membengkokkan kenyataan agar sesuai dengan model. Masalahnya adalah ketika Anda membengkokkan barang-barang agar sesuai (seperti tas meninju yang dapat meninju benda-benda) dunia yang Anda ciptakan menjadi semakin kompleks dan interaksi menjadi semakin sulit untuk diimplementasikan. Anda akhirnya akan mencapai titik di mana menambahkan bahkan hal yang paling sepele menjadi mimpi buruk dari perubahan dan bug. Utang teknis konseptual ini dapat memiliki harga yang sangat curam bahkan jika biaya awal dianggap pada saat itu sebagai hal termurah untuk dilakukan.

Newtopian
sumber
1

Ini adalah masalah yang saya sebut kebingungan "objek / subjek" dan cukup lazim.

Kalimat umumnya memiliki subjek yang melakukan kata kerja pada objek target mereka .

Sekarang berkaitan dengan pemrograman satu-satunya hal yang benar-benar melakukan sesuatu adalah komputer. Atau hampir suatu proses, benang atau serat. Objek tidak hidup secara default. Mereka tidak memiliki utas sendiri yang berjalan sehingga mereka tidak bisa melakukan apa-apa.

Ini berarti metode beroperasi pada mereka, mereka adalah target tindakan bukan siapa yang melakukan tindakan. Itu sebabnya kami menyebutnya "objek" bukan "subjek"!

Ketika Anda mengatakan File.closeitu bukan file yang menutup sendiri, itu utas berjalan saat ini yang menutup file. Jika Anda mengatakan Array.sort, utas berjalan saat ini mengurutkan array. Jika Anda mengatakan HttpServer.sendRequest, utas berjalan saat ini mengirimkan permintaan ke server (bukan sebaliknya!). Dengan PunchingBag.punchcara yang sama mengatakan bahwa benang yang sedang berjalan meninju tas.

Ini berarti jika Anda ingin Boxerdapat meninju, maka harus subclass dari Threadsehingga dapat melakukan hal-hal seperti meninju tas di fungsi utasnya.

Namun kadang-kadang juga masuk akal untuk mengatakan meninju karung tinju sendiri dalam kasus di mana setiap objek memiliki utas Anda sendiri, Anda mungkin ingin menghindari kondisi balapan dan menerapkan metode panggilan sebagai pesan lewat: Anda meninju tas dengan mengirimkannya punchpesan, itu tusukan benang itu sendiri kemudian mengirim Anda kembali punch successfulpesan, tapi itu hanya detail implementasi.

Calmarius
sumber
0

Saya setuju bahwa "punch" adalah nama metode yang bagus untuk kelas Boxer, karena (dengan beberapa penyesuaian) dapat digunakan kembali terhadap objek lain. Ini juga secara akurat menggambarkan bahwa suatu objek kelas sedang melakukan suatu tindakan pada objek lain. Padahal, saya akan mengganti nama metode menjadi "doPunch", untuk lebih jelas menunjukkan hubungannya.

Namun untuk kelas PunchingBag, saya menemukan nama metode terlalu samar atau sedikit tidak akurat tentang apa yang terjadi dalam metode ini. Ketika saya melihat "pukulan", saya pikir ada sesuatu yang meninju sesuatu yang lain. Namun, di sini, objek PunchingBag bereaksi terhadap pukulan dari suatu objek (dalam hal ini, objek Boxer). Jadi, saya akan mengganti nama metode di sini menjadi "isPunched" untuk menggambarkan bahwa objek bereaksi terhadap sebuah pukulan.

Padahal, ini adalah interpretasi saya tentang bagaimana saya akan menyebutkan metode. Ini semua masalah selera dan standar apa yang Anda ikuti.

Marvon
sumber
3
isPunchedbenar-benar menyesatkan (lebih atau kurang, tergantung pada skema penamaan kerangka kerja).
Biasanya metode itu diterapkan pada objek itu, yang disebutnya. Apa yang salah dengan adil punch()?
Yah, saya benar-benar mengerti bahwa perlu menentukan arah tindakan tetapi saya pikir ada sesuatu tentang OOP dan filosofi yang membuat ini tidak perlu. Semacam abstraksi yang terhubung dengan penjelasan terkenal itu yang saling "mengirim pesan" satu sama lain.
iklim
Jika tidak jelas dari nama metode apa metode yang dilakukan maka itu masalah dengan namanya. Ini bukan masalah dengan OO atau paradigma apa pun yang digunakan. Itu sebabnya pukulan () pada tas tinju salah dalam konteks apa pun yang Anda ingin gunakan. Apa artinya ketika Anda mengatakan meninju ke tas tinju? Itu juga mengapa Anda tidak dapat berasumsi dengan filosofi apa pun bahwa ada sesuatu yang tidak perlu dalam situasi di mana asumsi menciptakan ambiguitas. Ada kasus di mana aturan praktis bekerja dan situasi di mana aturan itu tidak berlaku. Jika aturan praktis selalu bekerja maka mereka akan disebut aturan (tanpa "praktis").
Dunk
-2

hmmmm Saya mempertanyakan karung tinju sebagai kelas, karena Anda tidak benar-benar peduli dengan karung tinju - Anda peduli tentang dampak dan kekuatan tinju Boxers. jadi metode harus tentang apa pun yang mengukur dan melaporkan dampak pukulan. bahkan jika ini berasal dari 'karung tinju', penamaan masih harus mengungkapkan tanggung jawab - seperti punchImpactMeter dll.

kereta dorong
sumber
-3

Boxer itu meninju kantong punching -> boxer.punch

Karung tinju akan ditinju oleh petinju -> punchingbag.get_punch

P3Dr0
sumber
3
ini tampaknya tidak menawarkan sesuatu yang substansial atas poin yang dibuat dan dijelaskan dalam 6 jawaban sebelumnya
nyamuk