OOP ilkeleri ve yöntem adları


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)

Hiç şüphe yok ki bu punchbir boksör durumunda iyi bir yöntem adıdır. Ama isim punchaynı zamanda boks torbası metodu için iyi mi? Her iki durumda da, bir komut olarak yumruk demek istiyorum (yani, yumruk yapmak).

Yanıtlar:


23

İyi bir kural, yöntem adlarının fiiller olması veya onları çağırdığınız nesnenin ( selfstandart Python kurallarında, thisdiğer dillerin çoğunda) konu haline gelmesi gerektiği anlamına gelmesidir.

Bu kural gereği, file.closedosyanın kendisini kapattığı zihinsel modele gitmediğiniz veya filenesnenin dosyanın kendisini temsil etmediği, aksine bir dosya tanıtıcısı veya bir tür proxy nesnesini temsil etmediği sürece, yanlış bir işlemdir.

Bir kum torbası yine de kendini yumruklayamaz, bu yüzden punchingBag.punch()her iki şekilde de yanlıştır. be_punched()teknik olarak doğru, ama çirkin. receive_punch()işe olabilecek veya handle_punch(). JavaScript oldukça popüler bir diğer yaklaşım, etkinlikleri gibi yöntem çağrıları tedavi etmektir ve bu olurdu böylece kongre, 'açık' öneki etkinlik adı, gitmek var on_punched()ya on_hit(). Alternatif olarak, geçmiş katılımcıların pasif sesi belirttiği sözleşmeyi kabul edebilirsiniz ve bu sözleşmeyle yöntem adı adil olacaktır punched().

Dikkate alınması gereken bir diğer husus ise kum torbasının gerçekten neyin çarptığını bilmesi olup olmadığıdır: Zımbalamanız, bir sopayla atmanız veya bir kamyona çarpmanız fark yaratır mı? Eğer öyleyse, fark nedir? Farkı bir tartışmaya indirgeyebilir misiniz, yoksa alınan çeşitli cezalar için farklı yöntemlere mi ihtiyacınız var? Genel bir parametreye sahip tek bir yöntem muhtemelen en zarif çözümdür, çünkü dereceyi düşük tutar ve böyle bir yöntem çağrılmamalıdır punched()ya da handle_punch()daha genel bir şey gibi olmalıdır receive_hit(). Böyle bir yöntem uygulandığında, kum torbasının kendisini değiştirmeden kum torbası vurabilecek her türlü oyuncuyu uygulayabilirsiniz.


4
@Artur: evet ve hayır. Dosyalar (kavramsal olarak konuşulur) istendiğinde kendilerini kapatabilir; diziler kendilerini sıralayabilir; ancak kum torbaları kendilerini yumruklamaz.
tdammers

2
Tamam, boks torbamız duvara çılgınca bir hızla çarparsa, onu yumruklayan duvar mıdır, yoksa kum torbasının kendine ve aslında kendisi tarafından vurulduğunu mu hissediyordu?

1
@tdammers: Genelleştirme önerin, denilen bir arayüze yol açabilir Hitable.
Jens Piegsa

2
@Artur: Bence OOP, her cümlenin doğal bir özneye sahip olduğunu ve bu fikrin programlama için geçerli olduğunu varsaydığı yer olduğunu düşünüyorum.
tdammers

1
Yani ana soru. Dosyalar kendilerini kapatabilirlerse, diziler kendilerini sıralayabilirler, vb. Neden kum torbaları kendilerini yumruklayamıyor? Gerçek bir fark var mı, yoksa sadece ilk durumda buna alıştık ve ikinci durumda değil miyiz?
clime

6

Bunun kavramsal bir mesele olduğunu düşünüyorum (dünya hakkında nasıl düşündüğümüz). Söylemek tamam:

  • Bak, kapı kapanıyor. door.close()
  • Vay, kağıt kendi kendine katlanıyor. paper.fold()
  • Ne oluyor be?! Masanın üzerindeki dosya kapandı, etrafta kimse yok. file.close()

Söylemek garip:

  • Spor salonundaki boks torbası kendine yeni yumruk attı. bag.punch()

İlk etapta kendisini yumruklayacak bir şeye sahip olması gerekir (örneğin silahlar). Muhtemelen söylersiniz:

  • Kum torbası, birisinin yumruklamış olduğu gibi kendi kendine hareket etmeye başladı. punching_bag.move()

Programatik nesnelerin normalde başkalarının kendisiyle / onunla yaptığı şeyleri yapması iyidir ("gerçek dünyada"). Ama sanırım en azından bir şeyin kendisiyle / onunla yaptığı bir anlam ifade etmeli . Gizlenmeden kolayca hayal edebilmelisiniz (durumunda olduğu gibi punching_bag).


2

Tat meselesi sanırım. Punching bag'ın punch()metodu en azından kendisi ile ilgili eylem deneyimlemekle file.close()veya frame.move()anlamıyla tutarlı . Daha büyük soru, neden Boxerhiç punch(something)yöntem var ki?


File.close () hakkındaki noktanı beğeniyorum. Aldığım bir şeydi. Belki boksörün yumruklama metodu vardır, çünkü boksörü eğiten bir antrenör de vardır. Aslında, sadece sonuncusu "bir eylemin nesnesi" olan birkaç nesneden geçen bir eylem (mesaj) örneği vermeye çalışıyordum. List.append (4), account.deposit (50), file.close (), paper.fold () vs. boxer.punch (), dog.bark (), logger.log () etc ile ilgili ufak bir sorunum var. .
clime

Birkaç nesneyi geçerken, iki durum vardır: ilişkili bağlamı kullanırsınız (öz) ve yapmazsınız. Bunu yaparsanız, sizin yöntemler olmalıdır Coach.sayPunchToBoxer(), Boxer.punchNearestBag()ve Bag.punch(). Aksi halde, her aradığınızda ne olacağını tahmin etmeniz gerekir Coach.punch(). Genel kural şudur: eylem yaşayan nesne yöntem adında belirtilmezse, alıcı o nesnedir.

Eh, bence bu da doğru: coach.say_punch (boksör, boks torbası), boksör.punch (boks torbası). yani alıcı yöntem adına değil, parametrelere göredir.
clime

1
Elbette, eylem alıcısının call deyiminden tahmin edilebilir olması gerektiğini kastettim.

2

İki farklı mesajınız vardır: bir nesneye yumruk atması ve bir nesneye yumruklandığını bildirmesi için. Bir Boxer nesnesinin muhtemelen her ikisine de yanıt vermesi gerekeceğini düşünün . Farklı . Bu onlara farklı isimler vermek için gerçekten iyi bir neden.

Benim eğilimim, bunun punch(boxer, object, strength)karşıt yöntemini korumak ve yeniden adlandırmak olacaktır punched. Onu handle_punchya da onun gibi bir şeyi arayabilirsin ama sonra bir yumruk komutunu ya da yumruklandığına dair bir bildirimde bulunup bulunmadığı hala belirsiz.


Boxer'ın hem yumruk hem de handle_punch gibi bir şeye ihtiyacı olduğuna dair iyi bir nokta ( defendbu özel durumda olabilir). Ancak kum torbası asla böyle iki yönlü olmayacak. Ve zaten bu dosya var. Close () ...
clime

defendbir komuttur. Bir nesnenin yanıt olarak gerçekleştirebileceği olası bir eylemdir punched, ancak diğer nesnelerin defenddoğrudan çağırmasını istemezsiniz .
user2313838

2

Yaklaşımınız sonunda çok birleştirilmiş kod yol açacaktır.

İdeal olarak Eric Lippert'i burada özetlemek için , boksörün birçok şeyi yumruklayabilmesini istersiniz. Boks torbasının boksör fonksiyonunun imzası olarak sahip olması, boksörün hemen (Tümü delinebilir) bilgisi ile yaratıldığı anlamına gelir. Ayrıca bir yumruk vermek ve bir yumruk almak iki ÇOK farklı şeydir, bu yüzden aynı adı paylaşmamalıdırlar.

Bunu bir yumruk oluşturan bir boksör olarak modellemeyi tercih ederim (delginin nitelik gücünü içeren bir başka nesne, erişim, yön vb.).

Daha sonra boks torbasını, bu delme nesnesini alan onPunch gibi bir yöntemle delginin kendi üzerindeki etkisini hesaplayabilir.

Bunu akılda tutmak, olayların adı çok önemlidir. Bu durumun sahip olduğunuz zihinsel modeline uygun olmalıdır. Kendinizi ilk görüşte anlam ifade etmeyen bir şeyin nasıl olabileceğini açıklamaya çalışırken bulursanız ya da bir şeyi adlandırmak için en zor zamana sahip değilseniz, belki de modeliniz yanlıştır ve değişmesi gerekir.

Başladıktan sonra bir modeli değiştirmek zor, insanlar genellikle modele uyması için gerçeği bükme eğilimindedir. Bununla ilgili sorun, uydurduğunuz şeyleri (nesneleri yumruklayabilen bir boks torbası gibi) bükerken, yarattığınız dünya giderek daha karmaşık hale gelir ve etkileşimlerin uygulanması giderek zorlaşır. Sonunda, en önemsiz şeyi eklemenin bile değişikliklerin ve hataların kabusu haline geldiği bir noktaya varacaksınız. Bu kavramsal teknik borcun, başlangıçtaki maliyet yapılacak en ucuz şey olarak algılanmış olsa bile çok yüksek bir fiyatı olabilir.


1

Bu benim “nesne / özne” kargaşası dediğim sorun ve oldukça yaygın.

Cümlelerin genellikle fiillerini hedef nesnesinde yapan bir öznesi vardır .

Şimdi, programlama ile ilgili olarak aslında bir şeyler yapan tek şey bilgisayardır. Ya da neredeyse bir süreç, iplik ya da bir elyaf. Nesneler varsayılan olarak canlandırılmaz. Kendi iş parçacıklarını çalıştırıyorlar, yani gerçekten hiçbir şey yapamıyorlar.

Bu, metotların kendileri üzerinde işlem gördüğü anlamına gelir, onlar eylemi yapanların değil eylemin hedefidir. Bu yüzden onlara “konu” değil “nesne” diyoruz!

File.closeDosyanın kendi kapanmadığını söylerken , dosyayı kapatan güncel çalışan iş parçacığıdır. Söylerseniz Array.sort, geçerli çalışan iş parçacığı diziyi sıralar. Söylerseniz HttpServer.sendRequest, geçerli çalışan iş parçacığı isteği sunucuya gönderir (bunun tersi değil!). Benzer şekilde PunchingBag.punch, şu anki çalışan iplik torbayı delmek anlamına gelir.

Bu Boxer, Threadzımbalanabilmeyi istiyorsanız , o zaman onun alt fonksiyonunda kum torbası gibi şeyleri yapabilmesi için alt sınıf olması gerekir .

Ancak bazen, kum torbasının, her nesnenin kendi dişine sahip olması durumunda, yarış koşullarından kaçınmak ve yöntem çağrıları mesaj geçişi olarak uygulamak isteyebileceğiniz durumlarda, yumruk torbasının kendisini yumrukladığını söylemek mantıklı olur: mesajı göndererek torbayı punchyumruklarsınız; kendisi daha sonra punch successfulmesajı size geri gönderir , ancak bu sadece bir uygulama detayıdır.


0

"Yumruk" un Boxer sınıfı için iyi bir yöntem adı olduğunu kabul ediyorum (bazı ince ayarlarla) diğer nesnelere karşı yeniden kullanılabiliyor. Ayrıca, bir sınıfın nesnesinin başka bir nesne üzerinde bir eylem yaptığını doğru bir şekilde tarif eder. Yine de, ilişkiyi daha net göstermek için, yöntemi "doPunch" olarak değiştirirdim.

Bununla birlikte, PunchingBag sınıfı için, yöntem adının yöntemde olup bitenlerden çok belirsiz veya biraz yanlış olduğunu tespit ediyorum. "Yumruğu" gördüğümde, bir şeyin başka bir şeyi yumrukladığını düşünüyorum. Bununla birlikte, burada, PunchingBag nesnesi bir nesneden bir zımbaya tepki veriyor (bu durumda, bir Boxer nesnesi). Bu nedenle, buradaki yöntemi, nesnenin bir zımbaya tepki gösterdiğini göstermek için "isPunched" olarak değiştiririm.

Yine de, bu yöntemleri nasıl adlandıracağım konusundaki yorumum. Hepsi bir zevk meselesi ve hangi standartları takip ettiğinizle ilgili.


3
isPunchedgerçekten yanıltıcıdır (çerçeve adlandırma düzenine bağlı olarak az ya da çok).

Bu yöntemin, üzerinde çağrıldığı nesneye uygulanması olağandır. Sadece yanlış olan ne punch()?

Eylem yönünü belirtmesi gerektiğini tamamen anlıyorum, ancak OOP ve bunun felsefesi için gereksiz olan bir şey olduğunu düşünüyorum. Birbirlerine "mesaj gönderen" itiraz eden meşhur açıklama ile bağlantılı bir tür soyutlama.
clime

Metodun isminde metodun ne yaptığı belli değilse, o ismin problemidir. OO ile ya da hangi paradigma kullanılıyorsa, bu bir sorun değildir. Bu yüzden, kum torbasına punch () koymak istediğiniz bağlamda yanlış. Kum torbasına yumruk attığın ne demek? Aynı zamanda, herhangi bir felsefeyle varsayımın belirsizlik yarattığı durumlarda bir şeyin gereksiz olduğunu kabul edememenizin nedeni de budur. Temel kuralların işe yaradığı durumlar ve çalışmadıkları durumlar vardır. Başparmak kuralları her zaman işe yararsa, o zaman kurallar ("başparmağın" olmadan) denirdi.
Dunk

-2

hmmmm. Kum torbasını bir sınıf olarak sorgulayacağım çünkü kum torbasını gerçekten önemsemiyorsunuz - Boksör yumruklarının etkisini ve gücünü önemsiyorsunuz. bu nedenle, yöntemler, zımba etkisini ölçen ve rapor edenle ilgili olmalıdır. Bu 'boks torbasından' gelse bile, isimlendirmenin hala sorumluluğu - punchImpactMeter vb.


-3

Boksör kum torbasına yumruk atıyor -> boxer.punch

Boks Torbası boksör tarafından yumruklanır -> punchingbag.get_punch


3
bu, önceki 6
cevapta
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.