Kỹ thuật giảm thiểu số lượng đối số chức năng


13

Trong Clean Code, người ta viết rằng "số lượng đối số lý tưởng cho hàm là 0". Những lý do tại sao được giải thích và có ý nghĩa. Những gì tôi đang theo là các kỹ thuật để cấu trúc lại các phương thức với 4 hoặc nhiều đối số để giải quyết vấn đề này.

Một cách là trích xuất các đối số vào một lớp mới, nhưng điều đó chắc chắn sẽ dẫn đến sự bùng nổ của các lớp? Và các lớp đó có khả năng kết thúc bằng các tên vi phạm một số quy tắc đặt tên (kết thúc bằng "Dữ liệu" hoặc "Thông tin", v.v.)?

Một kỹ thuật khác là biến các biến được sử dụng bởi nhiều hàm thành một biến thành viên riêng để tránh truyền chúng, nhưng điều đó mở rộng phạm vi của biến, có thể là nó mở cho các hàm không thực sự cần nó.

Chỉ cần tìm cách để giảm thiểu các đối số chức năng, đã chấp nhận các lý do tại sao nên làm như vậy.


21
Tbh tôi không đồng ý với mã sạch. Nếu số lượng đối số cho một hàm bằng 0 thì điều đó có nghĩa là hàm đó có tác dụng phụ và có thể thay đổi trạng thái ở đâu đó. Mặc dù tôi đồng ý rằng ít hơn 4 đối số có thể là một quy tắc tốt - tôi muốn có một hàm có 8 đối số là tĩnh và không có tác dụng phụ hơn một hàm không tĩnh với các đối số bằng 0 thay đổi trạng thái và có tác dụng phụ .
wasatz

4
" Trong Clean Code, người ta viết rằng" số lượng đối số lý tưởng cho hàm là 0 ". " Thật sao? Điều đó thật sai lầm! Số lượng tham số lý tưởng là một, với giá trị trả về được xác định xuất phát từ một tham số đó. Trong thực tế, số lượng tham số không quan trọng lắm; Vấn đề là, bất cứ khi nào có thể, hàm phải thuần túy (nghĩa là nó chỉ lấy giá trị trả về từ các tham số không có tác dụng phụ).
David Arno

2
Chà, cuốn sách sau này tiếp tục chỉ ra rằng các tác dụng phụ không được mong muốn ...
Neil Barnwell

2
Bản sao có thể có của Chiến lược để gói tham số
gnat

Câu trả lời:


16

Điều quan trọng nhất cần nhớ là đó là những hướng dẫn, không phải là quy tắc.

Có những trường hợp một phương thức đơn giản phải lấy một đối số. Hãy suy nghĩ về +phương pháp cho các số, ví dụ. Hoặc addphương pháp cho một bộ sưu tập.

Trong thực tế, người ta thậm chí có thể lập luận rằng ý nghĩa của việc thêm hai số phụ thuộc vào ngữ cảnh, ví dụ như trong ℤ 3 + 3 == 6, nhưng trong ℤ | 5 3 + 3 == 2 , vì vậy, toán tử bổ sung phải là một phương thức trên một đối tượng bối cảnh có hai đối số thay vì một đối số phương pháp trên các số có một đối số.

Tương tự, một phương thức để so sánh hai đối tượng phải là phương thức của một đối tượng lấy đối tượng kia làm đối số hoặc phương thức của bối cảnh, lấy hai đối tượng làm đối số, vì vậy đơn giản là không có phương thức so sánh với ít hơn một đối số.

Điều đó nói rằng, có một vài điều có thể được thực hiện để giảm số lượng đối số cho một phương thức:

  • Làm cho phương thức tự nhỏ hơn : Có thể, nếu phương thức cần nhiều đối số, thì nó đang làm quá nhiều?
  • Một sự trừu tượng bị thiếu : Nếu các đối số có mối tương quan chặt chẽ với nhau, có thể chúng thuộc về nhau và có một sự trừu tượng hóa mà bạn đang thiếu? (Ví dụ về sách giáo khoa Canonical: thay vì hai tọa độ, truyền một Pointđối tượng hoặc thay vì chuyển tên người dùng và email, hãy chuyển một IdCardđối tượng.)
  • Trạng thái đối tượng : Nếu đối số là cần thiết bởi nhiều phương thức, có lẽ nó phải là một phần của trạng thái đối tượng. Nếu nó chỉ cần một số phương thức chứ không phải các phương thức khác, có thể đối tượng đang làm quá nhiều và thực sự phải là hai đối tượng.

Một cách là trích xuất các đối số vào một lớp mới, nhưng điều đó chắc chắn sẽ dẫn đến sự bùng nổ của các lớp?

Nếu mô hình miền của bạn có nhiều loại khác nhau, thì mã của bạn sẽ kết thúc với nhiều loại đối tượng khác nhau. Không có gì sai với điều đó.

Và các lớp đó có khả năng kết thúc bằng các tên vi phạm một số quy tắc đặt tên (kết thúc bằng "Dữ liệu" hoặc "Thông tin", v.v.)?

Nếu bạn không thể tìm thấy một tên thích hợp, có thể bạn đã nhóm quá nhiều đối số lại với nhau hoặc quá ít. Vì vậy, bạn chỉ có một mảnh của một lớp hoặc bạn có nhiều hơn một lớp.

Một kỹ thuật khác là biến các biến được sử dụng bởi nhiều hàm thành một biến thành viên riêng để tránh truyền chúng, nhưng điều đó mở rộng phạm vi của biến, có thể là nó mở cho các hàm không thực sự cần nó.

Nếu bạn có một nhóm phương thức tất cả các phương thức hoạt động trên cùng một đối số và một nhóm phương thức khác không có, có thể chúng thuộc các lớp khác nhau.

Lưu ý tần suất tôi sử dụng từ "có thể"? Đó là lý do tại sao đó là hướng dẫn, không phải là quy tắc. Có lẽ phương pháp của bạn với 4 tham số là hoàn toàn tốt!


7
@ BrunoSchäpper: Chắc chắn: (1) " Làm cho phương thức tự nhỏ hơn: Có thể, nếu phương thức cần nhiều đối số, thì nó có làm quá nhiều không? ". Số lượng params là một bài kiểm tra kém về điều này. Các tham số tùy chọn / boolean và rất nhiều dòng mã là các chỉ số mạnh của một phương thức làm quá nhiều. Nhiều params tốt nhất là một yếu. (2) " Trạng thái đối tượng: Nếu đối số là cần thiết cho nhiều phương thức, có lẽ nó phải là một phần của trạng thái đối tượng ". Không, không và ba lần, không. Giảm thiểu trạng thái đối tượng; không tham số chức năng. Nếu có thể truyền một giá trị cho tất cả các phương thức thông qua các tham số để tránh trạng thái đối tượng.
David Arno

Ví dụ bạn đưa ra để bổ sung là không đúng. Các addchức năng cho các số tự nhiên và các addchức năng cho chiếc nhẫn của số nguyên mod n là hai chức năng hành động khác nhau trên hai loại khác nhau. Tôi cũng không hiểu ý bạn là gì bởi "bối cảnh".
vườn

Thx @DavidArno. 1) đồng ý, không phải là một chỉ số mạnh trong và của chính nó. Nhưng dù sao cũng là một người tốt. Tôi thường thấy một vài phương thức, với một vài đối tượng được truyền vào arround. Không có trạng thái đối tượng. Đó là điều tốt, nhưng 2) tùy chọn tốt hơn IMHO đang cấu trúc lại các phương thức đó, chuyển trạng thái ẩn sang một lớp mới, lấy tất cả các tham số này làm đối số rõ ràng. Bạn kết thúc với một phương thức đối số zero công khai và rất nhiều phương thức bên trong đối số zero-to-one. Nhà nước không công khai, toàn cầu hoặc thậm chí được duy trì lâu dài, nhưng mã sạch hơn rất nhiều.
Bruno Schäpper

6

Lưu ý rằng không có đối số nào không ngụ ý tác dụng phụ, bởi vì đối tượng của bạn là đối số ngầm. Ví dụ, hãy xem có bao nhiêu phương pháp khôngdanh sách của Scala .

Một kỹ thuật hữu ích tôi gọi là kỹ thuật "lấy nét ống kính". Khi bạn lấy nét ống kính máy ảnh, sẽ dễ dàng hơn để nhìn thấy điểm lấy nét thực sự nếu bạn đưa nó đi quá xa, sau đó đưa nó trở lại điểm chính xác. Điều tương tự cũng đúng với tái cấu trúc phần mềm.

Đặc biệt nếu bạn đang sử dụng kiểm soát phiên bản phân tán, các thay đổi phần mềm rất dễ thử nghiệm, hãy xem bạn có thích giao diện của chúng không và tắt đi nếu bạn không, nhưng vì một số lý do, mọi người thường có vẻ miễn cưỡng làm như vậy.

Trong ngữ cảnh của câu hỏi hiện tại của bạn, điều đó có nghĩa là viết các phiên bản không hoặc một đối số, với một số chức năng được tách ra trước, sau đó tương đối dễ dàng để xem các chức năng nào cần kết hợp để dễ đọc.

Lưu ý rằng tác giả cũng là một người ủng hộ rất lớn cho sự phát triển dựa trên thử nghiệm, có xu hướng tạo ra các hàm có độ yếu thấp ngay từ đầu vì bạn bắt đầu với các trường hợp thử nghiệm tầm thường của mình.


1
Giống như sự tương tự "lấy nét ống kính" của bạn - Đặc biệt là khi tái cấu trúc, điều quan trọng là sử dụng ống kính góc rộng thay vì ống kính cận cảnh. Và nhìn vào # các tham số đơn giản là quá gần
tofro

0

Một cách tiếp cận đơn giản (và ngây thơ - hoặc thậm chí tôi nên nói một cách mù quáng ) chỉ nhằm mục đích giảm số lượng đối số cho các hàm ist có thể sai. Hoàn toàn không có gì sai với các hàm có số lượng lớn đối số. Nếu chúng được logic yêu cầu, thì chúng cũng được yêu cầu ... Một danh sách tham số dài hoàn toàn không làm tôi lo lắng - miễn là nó được định dạng đúng và nhận xét về tính dễ đọc.

Trong trường hợp tất cả hoặc một tập hợp con của các đối số thuộc về một thực thể logic duy nhất và thường được truyền xung quanh trong các nhóm trong suốt chương trình của bạn, có thể có ý nghĩa khi nhóm chúng vào một thùng chứa - Điển hình là một cấu trúc hoặc đối tượng khác. Ví dụ điển hình có thể là một số loại thông điệp hoặc kiểu dữ liệu sự kiện .

Bạn có thể dễ dàng làm quá mức phương pháp đó - một khi bạn thấy rằng việc đóng gói và giải nén các thứ đến và từ các container vận chuyển như vậy sẽ tạo ra nhiều chi phí hơn là cải thiện khả năng đọc, có lẽ bạn đã đi quá xa.

OTOH, danh sách tham số lớn có thể là dấu hiệu cho thấy chương trình của bạn có thể không được cấu trúc đúng - có thể chức năng yêu cầu số lượng lớn tham số như vậy chỉ là cố gắng làm quá nhiều và nên được chia thành nhiều chức năng nhỏ hơn. Tôi muốn bắt đầu ở đây hơn là lo lắng về # tham số.


5
Tất nhiên, giảm số lượng đối số là sai. Nhưng tôi không đồng ý với "Hoàn toàn không có gì sai với các hàm có số lượng lớn đối số." . Theo tôi, khi bạn nhấn một hàm có số lượng đối số lớn, trong 99,9% trong tất cả các trường hợp, có một cách để cải thiện cấu trúc mã theo cách có chủ ý, điều này cũng làm giảm số lượng đối số của hàm.
Doc Brown

@DocBrown Đó là lý do tại sao có đoạn cuối cùng này và đề xuất bắt đầu từ đó .... Và một điều khác: Có lẽ bạn chưa bao giờ thử lập trình chống lại API MS Windows;)
tofro

"có thể chức năng yêu cầu số lượng lớn các tham số như vậy chỉ là cố gắng làm quá nhiều và nên được chia thành nhiều chức năng nhỏ hơn." Tôi hoàn toàn đồng ý, mặc dù trong thực tế, bạn không kết thúc với một chức năng khác cao hơn ngăn xếp gọi một số chức năng nhỏ hơn? Sau đó, bạn có thể cấu trúc lại chúng thành một đối tượng, nhưng đối tượng đó sẽ có một ctor. Bạn có thể sử dụng một người xây dựng blah blah blah. Vấn đề là đó là một hồi quy vô hạn - ở đâu đó, có một số giá trị cần thiết cho phần mềm để thực hiện công việc của mình và bằng cách nào đó chúng phải có được các chức năng đó.
Neil Barnwell

1
@NeilBarnwell Trong trường hợp lý tưởng (đáng để tái cấu trúc), bạn có thể chia một hàm cần 10 đối số thành ba đối số cần 3-4 đối số mỗi đối số. Trong trường hợp không lý tưởng, bạn kết thúc với ba hàm cần 10 đối số mỗi hàm (tốt hơn là để nó một mình, sau đó). Liên quan đến đối số ngăn xếp cao hơn của bạn: Đồng ý - Có thể là trường hợp, nhưng không nhất thiết - các đối số đến từ đâu đó và việc truy xuất đó cũng có thể ở đâu đó trong ngăn xếp và chỉ cần được đặt vào vị trí thích hợp ở đó - Mileage có xu hướng thay đổi.
tofro

Logic phần mềm không bao giờ yêu cầu nhiều hơn bốn tham số. Chỉ một trình biên dịch có thể.
theDoctor

0

Không có cách kỳ diệu: bạn phải nắm vững miền vấn đề để khám phá kiến ​​trúc phù hợp. Đó là cách duy nhất để cấu trúc lại: làm chủ miền vấn đề. Hơn bốn tham số chỉ là một sự chắc chắn rằng kiến ​​trúc hiện tại của bạn bị lỗi và sai.

Các ngoại lệ duy nhất là trình biên dịch (siêu dữ liệu) và mô phỏng, trong đó giới hạn là lý thuyết 8, nhưng có lẽ chỉ có 5.

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.