Nguyên tắc OOP và tên phương thức


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)

Không có nghi ngờ rằng đó punchlà một tên phương pháp tốt trong trường hợp của một võ sĩ. Nhưng tên punchcũng tốt cho phương pháp đấm túi? Trong cả hai trường hợp, tôi có nghĩa là đấm như một lệnh (tức là làm cú đấm).

Câu trả lời:


23

Một nguyên tắc nhỏ là tên phương thức phải là động từ hoặc vị ngữ sao cho đối tượng bạn gọi chúng ( selftheo quy ước Python chuẩn, thistrong hầu hết các ngôn ngữ khác) trở thành chủ đề.

Theo quy tắc này, file.closelà loại sai, trừ khi bạn đi với mô hình tinh thần mà tệp tự đóng hoặc fileđối tượng không đại diện cho chính tệp đó, mà là xử lý tệp hoặc một loại đối tượng proxy.

Một túi đấm không bao giờ tự đấm, mặc dù vậy punchingBag.punch()cũng là sai. be_punched()là đúng kỹ thuật, nhưng xấu xí. receive_punch()có thể làm việc, hoặc handle_punch(). Một cách tiếp cận khác, khá phổ biến trong JavaScript, là coi các cuộc gọi phương thức đó là các sự kiện và quy ước phải đi kèm với tên sự kiện, có tiền tố là 'bật', do đó sẽ là on_punched()hoặc on_hit(). Ngoài ra, bạn có thể chấp nhận quy ước rằng những người tham gia trong quá khứ biểu thị tiếng nói thụ động và theo quy ước đó, tên phương thức sẽ là chính xác punched().

Một khía cạnh khác cần xem xét là liệu túi đấm có thực sự biết thứ gì đánh vào nó hay không: nó có tạo ra sự khác biệt cho dù bạn đấm nó, đánh nó bằng gậy hay chạy vào nó bằng xe tải? Nếu vậy, sự khác biệt là gì? Bạn có thể rút ra sự khác biệt cho một cuộc tranh cãi, hoặc bạn có cần các phương pháp khác nhau cho các loại hình phạt nhận được khác nhau không? Một phương thức duy nhất có tham số chung có lẽ là giải pháp tao nhã nhất, bởi vì nó giữ cho mức độ khớp nối ở mức thấp và phương thức như vậy không nên được gọi punched()hoặc handle_punch(), mà là một cái gì đó chung chung hơn receive_hit(). Với phương pháp như vậy, bạn có thể thực hiện tất cả các loại diễn viên có thể đánh túi đấm, mà không cần thay đổi túi đấm.


4
@Artur: có và không. Các tập tin có thể (nói theo khái niệm) tự đóng lại khi được hỏi; mảng có thể tự sắp xếp; nhưng túi đấm không tự đấm.
tdammers

2
Được rồi, nếu túi đấm của chúng tôi đập vào tường với tốc độ điên cuồng, thì đó có phải là bức tường đã đấm nó không, hay nó là túi đấm có kinh nghiệm đánh vào chính nó và thực sự là chính nó?

1
@tdammers: Đề xuất của bạn để khái quát hóa cũng có thể dẫn đến một giao diện được gọi Hitable.
Jens Piegsa

2
@Artur: Tôi nghĩ rằng đây là nơi mà giả định OOP rằng mọi câu đều có chủ đề tự nhiên và ý tưởng này có thể áp dụng cho lập trình, bị phá vỡ.
tdammers

1
Vì vậy, câu hỏi chính là. Nếu các tệp có thể tự đóng, các mảng có thể tự sắp xếp, v.v., tại sao túi đấm không thể tự đấm? Có sự khác biệt thực sự hay chỉ là trong trường hợp đầu tiên, chúng ta đã quen với nó và trong lần thứ hai, chúng ta không?
clime

6

Tôi nghĩ đó là một vấn đề khái niệm (cách chúng ta nghĩ về thế giới). Không sao để nói:

  • Nhìn kìa, cánh cửa đang đóng lại. door.close()
  • Wow, tờ giấy đang tự gấp. paper.fold()
  • Cái quái gì thế?! Tập tin đó trên bàn vừa đóng, không có ai ở quanh. file.close()

Thật kỳ lạ khi nói:

  • Cái túi đấm đó trong phòng tập vừa tự đấm. bag.punch()

Nó sẽ cần phải có một cái gì đó để tự đấm vào ngay từ đầu (ví dụ như cánh tay). Bạn có thể sẽ nói:

  • Chiếc túi đấm đã bắt đầu tự di chuyển giống như ai đó sẽ đấm nó. punching_bag.move()

Các đối tượng lập trình có thể làm những việc mà người khác thường làm / với họ (trong "thế giới thực"). Nhưng tôi đoán nó phải luôn luôn có ít nhất một số ý nghĩa rằng sự việc đang thực hiện nó với / với chính nó . Bạn sẽ có thể tưởng tượng nó dễ dàng mà không bị che khuất (như trong trường hợp punching_bag).


2

Đó là vấn đề của hương vị, tôi nghĩ. Punching bag's punch()phương pháp ít nhất là phù hợp với file.close()hoặc frame.move()trong cảm giác trải qua hành động trên chính nó. Câu hỏi lớn hơn là, tại sao Boxerkhông có punch(something)phương pháp nào cả?


Tôi thích quan điểm của bạn về file.close (). Đó là điều mà tôi đã nhận được. Có thể võ sĩ có phương pháp đấm vì cũng có huấn luyện viên huấn luyện võ sĩ. Thực tế, tôi chỉ cố gắng đưa ra một số ví dụ về một hành động (tin nhắn) được truyền qua một số đối tượng với đối tượng cuối cùng là "đối tượng của một hành động". Tôi có một chút vấn đề với list.append (4), account.deposit (50), file.close (), paper. Fold () so với boxer.punch (), dog.bark (), logger.log (), v.v. .
clime

Khi đi qua một số đối tượng, có 2 trường hợp: bạn sử dụng bối cảnh bị ràng buộc (bản thân) và bạn không. Nếu bạn làm như vậy, phương pháp của bạn nên Coach.sayPunchToBoxer(), Boxer.punchNearestBag()Bag.punch(). Nếu không, bạn phải đoán những gì sẽ xảy ra mỗi khi bạn gọi Coach.punch(). Quy tắc chung là: nếu đối tượng trải nghiệm hành động không được chỉ định trong tên phương thức, thì người nhận là đối tượng đó.

Chà, tôi nghĩ điều này cũng ổn cả: coach.say_punch (boxer, punching_bag), boxer.punch (punching_bag). tức là máy thu không nằm trong tên phương thức mà là các tham số.
clime

1
Chắc chắn, tôi có nghĩa là người nhận hành động nên có thể đoán được từ tuyên bố cuộc gọi.

2

Bạn có hai thông điệp khác nhau: một để ra lệnh cho một đối tượng đấm và một để thông báo cho một đối tượng rằng nó đã bị đấm. Hãy xem xét rằng một đối tượng Boxer có thể sẽ cần phải trả lời cả hai . Khác nhau . Đó là một lý do thực sự tốt để đặt cho họ những cái tên khác nhau.

Xu hướng của tôi sẽ là giữ punch(boxer, object, strength)và đổi tên phương pháp ngược lại thành punched. Bạn có thể gọi nó handle_punchhoặc một cái gì đó tương tự nhưng sau đó vẫn còn mơ hồ liệu nó có xử lý lệnh đấm hay thông báo rằng nó bị đấm hay không.


Một điểm hay về Boxer cần cả cú đấm và thứ gì đó như handle_punch (sẽ có defendtrong trường hợp cụ thể này). Nhưng túi đấm sẽ không bao giờ được hai chiều như thế. Và đã có tập tin này. Đóng () ...
clime

defendlà một mệnh lệnh. Đó là một hành động khả thi mà một đối tượng có thể thực hiện để đáp lại punched, nhưng bạn sẽ không muốn các đối tượng khác gọi defendtrực tiếp.
user2313838

2

Cách tiếp cận của bạn cuối cùng sẽ dẫn đến mã rất ghép.

Để tóm tắt lý tưởng của Eric Lippert ở đây, bạn muốn võ sĩ có thể đấm được nhiều thứ tuyệt vời. Có túi đấm là chữ ký của chức năng võ sĩ ngụ ý rằng võ sĩ được tạo ra với kiến ​​thức ngay lập tức về Tất cả (đó là cú đấm). Cộng với việc đấm và nhận cú đấm là hai điều RẤT khác nhau, do đó họ không nên chia sẻ cùng một tên.

Tôi thà mô hình hóa nó như một Boxer tạo ra một cú đấm (một vật thể khác chứa lực thuộc tính của cú đấm, tầm với, hướng, v.v.).

Sau đó, có túi đấm với một phương pháp như onPunch nhận đối tượng đấm này có thể tự tính toán hiệu ứng của cú đấm.

Giữ điều này trong tâm trí tên của những điều quan trọng rất nhiều. Nó phải phù hợp với mô hình tinh thần bạn có của tình huống. Nếu bạn thấy mình đang cố gắng giải thích làm thế nào điều gì đó có thể xảy ra mà không có ý nghĩa ngay từ cái nhìn đầu tiên, hoặc nếu bạn gặp khó khăn nhất trong việc đặt tên thì có lẽ mô hình của bạn đã sai và cần phải thay đổi.

Thật khó để thay đổi một mô hình sau khi bạn bắt đầu, mọi người thường có xu hướng uốn cong thực tế để phù hợp với mô hình. Vấn đề với điều này là khi bạn uốn cong mọi thứ cho phù hợp (chẳng hạn như túi đấm có thể đấm mọi thứ), thế giới bạn đang tạo ra ngày càng phức tạp hơn và các tương tác ngày càng khó thực hiện hơn. Cuối cùng bạn sẽ đạt đến một điểm mà việc thêm ngay cả những thứ tầm thường nhất trở thành cơn ác mộng của những thay đổi và lỗi. Khoản nợ kỹ thuật khái niệm này có thể có một mức giá rất cao ngay cả khi chi phí ban đầu được coi là điều rẻ nhất để làm.


1

Đây là vấn đề mà tôi gọi là sự nhầm lẫn "đối tượng / chủ đề" và nó khá phổ biến.

Các câu nói chung có một chủ ngữ thực hiện động từ trên đối tượng đích của chúng .

Bây giờ liên quan đến lập trình, điều duy nhất thực sự làm mọi thứ là máy tính. Hoặc hầu như một quá trình, chủ đề hoặc một sợi. Các đối tượng không được animate theo mặc định. Họ không có chủ đề riêng của họ đang chạy để họ thực sự không thể làm gì.

Điều này có nghĩa là các phương thức hoạt động trên chúng, chúng là mục tiêu của hành động chứ không phải ai thực hiện hành động đó. Đó là lý do tại sao chúng tôi gọi chúng là "đối tượng" chứ không phải "đối tượng"!

Khi bạn nói File.closeđó không phải là tệp tự đóng, thì luồng đang chạy sẽ đóng tệp. Nếu bạn nói Array.sort, luồng đang chạy sắp xếp mảng. Nếu bạn nói HttpServer.sendRequest, luồng đang chạy hiện tại sẽ gửi yêu cầu đến máy chủ (không phải ngược lại!). Nói tương tự PunchingBag.punchcó nghĩa là các chủ đề chạy hiện tại đấm túi.

Điều này có nghĩa là nếu bạn muốn Boxercó khả năng đấm, thì nó phải là một lớp con của Threadnó để nó có thể làm những việc như đấm túi trong chức năng luồng của nó.

Tuy nhiên, đôi khi cũng có ý nghĩa khi nói đấm túi tự đấm trong trường hợp mỗi đối tượng có luồng riêng, bạn có thể muốn tránh điều kiện cuộc đua và thực hiện các cuộc gọi phương thức khi gửi tin nhắn: bạn đấm túi bằng cách gửi punchtin nhắn, đó là cú đấm sau đó chính nó sẽ gửi lại cho bạn punch successfultin nhắn, nhưng đó chỉ là một chi tiết thực hiện.


0

Tôi đồng ý rằng "punch" là một tên phương thức tốt cho lớp Boxer, vì (với một số điều chỉnh) nó có thể được sử dụng lại để chống lại các đối tượng khác. Nó cũng mô tả chính xác rằng một đối tượng của một lớp đang thực hiện một hành động trên một đối tượng khác. Mặc dù vậy, tôi sẽ đổi tên phương thức thành "doPunch", để thể hiện rõ hơn mối quan hệ.

Tuy nhiên, đối với lớp PunchingBag, tôi thấy tên phương thức quá mơ hồ hoặc không chính xác một chút về những gì đang xảy ra trong phương thức. Khi tôi thấy "cú đấm", tôi nghĩ rằng có thứ gì đó đang đấm thứ khác. Tuy nhiên, ở đây, đối tượng PunchingBag đang phản ứng với một cú đấm từ một đối tượng (trong trường hợp này là đối tượng Boxer). Vì vậy, tôi sẽ đổi tên phương thức ở đây thành "isPunched" để minh họa rằng đối tượng đang phản ứng với một cú đấm.

Mặc dù, đây là cách giải thích của tôi về cách tôi sẽ đặt tên cho các phương thức. Tất cả là vấn đề của hương vị và tiêu chuẩn mà bạn đang tuân theo.


3
isPunchedlà thực sự sai lệch (nhiều hay ít, tùy thuộc vào sơ đồ đặt tên khung).

Thông thường phương thức được áp dụng cho đối tượng đó, trên đó nó được gọi. Có chuyện gì với chỉ punch()vậy?

Chà, tôi hoàn toàn hiểu rằng cần phải xác định hướng hành động nhưng tôi nghĩ có điều gì đó về OOP và triết lý của nó khiến điều này trở nên không cần thiết. Một số loại trừu tượng được kết nối với lời giải thích nổi tiếng đó là các đối tượng "gửi tin nhắn" cho nhau.
clime

Nếu không rõ ràng từ tên phương thức thì phương thức đó đang làm gì thì đó là một vấn đề với tên đó. Đó không phải là vấn đề với OO hay bất kỳ mô hình nào đang được sử dụng. Đó là lý do tại sao punch () trên túi đấm là sai trong bất kỳ bối cảnh nào bạn muốn sử dụng nó. Điều đó có nghĩa là gì khi bạn nói đấm vào túi đấm? Đó cũng là lý do tại sao bạn không thể giả định theo bất kỳ triết lý nào rằng một cái gì đó không cần thiết trong các tình huống mà giả định tạo ra sự mơ hồ. Có những trường hợp quy tắc của ngón tay cái làm việc và tình huống mà họ không. Nếu quy tắc ngón tay cái luôn hoạt động thì chúng sẽ được gọi là quy tắc (không có "ngón tay cái").
Dunk

-2

hmmmm Tôi đang nghi ngờ túi đấm như một lớp học, bởi vì bạn không thực sự quan tâm đến túi đấm - bạn quan tâm đến tác động và sức mạnh của nắm đấm Boxers. vì vậy các phương pháp nên là về bất cứ điều gì đang đo lường và báo cáo tác động của cú đấm. ngay cả khi điều này đến từ 'túi đấm', việc đặt tên vẫn phải tiết lộ trách nhiệm - như punchImpactMeter, v.v.


-3

Các võ sĩ đấm túi đấm -> boxer.punch

Đấm đấm bị đấm bởi võ sĩ -> punchingbag.get_punch


3
điều này dường như không cung cấp bất cứ điều gì đáng kể qua các điểm được thực hiện và giải thích trong 6 câu trả lời trước
gnat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.