Clean Code: Hàm có vài tham số [đã đóng]


48

Tôi đã đọc các chương đầu tiên của Clean Code của Robert C. Martin, và dường như nó khá hay, nhưng tôi có một nghi ngờ, trong một phần, nó được đề cập rằng nó tốt (về mặt nhận thức) rằng các chức năng nên có ít tham số càng tốt, nó thậm chí còn gợi ý rằng 3 hoặc nhiều tham số là quá nhiều cho một hàm (mà tôi thấy rất phóng đại và duy tâm), vì vậy tôi bắt đầu tự hỏi ...

Cả thực tiễn sử dụng biến toàn cục và truyền nhiều đối số trên hàm đều là thực tiễn lập trình xấu, nhưng việc sử dụng biến toàn cục có thể làm giảm đáng kể số lượng tham số trong hàm ...

Vì vậy, tôi muốn nghe những gì bạn nghĩ về nó, nó có đáng để sử dụng các biến toàn cục để giảm số lượng tham số của các hàm hay không? Trong trường hợp nào nó sẽ được?

Những gì tôi nghĩ là nó phụ thuộc vào một số yếu tố:

  • Kích thước mã nguồn.
  • Số lượng tham số trung bình của các chức năng.
  • Số lượng chức năng.
  • Tần suất trong đó các biến tương tự được sử dụng.

Theo tôi, nếu kích thước mã nguồn tương đối nhỏ (như dưới 600 dòng mã), có nhiều hàm, cùng một biến được truyền dưới dạng tham số và các hàm có nhiều tham số, thì sử dụng biến toàn cục sẽ có giá trị, nhưng tôi muốn biết ...

  • Bạn có chia sẻ ý kiến ​​của tôi không?
  • Bạn nghĩ gì về các trường hợp khác mà mã nguồn lớn hơn, v.v.?

PS . Tôi thấy bài đăng này , các tiêu đề rất giống nhau, nhưng anh ấy không hỏi những gì tôi muốn biết.


144
Tôi không nghĩ rằng giải pháp thay thế sẽ là toàn cầu, nhưng thay vào đó, hợp nhất các đối số thành các đối tượng. Có lẽ nhiều gợi ý postLetter(string country, string town, string postcode, string streetAddress, int appartmentNumber, string careOf)là phiên bản có mùi của postLetter(Address address). Tiếp tục đọc cuốn sách, nó hy vọng sẽ nói điều gì đó như thế.
Nathan Cooper

3
@DocBrown Tôi đã đặt câu hỏi có nghĩa giống như chú Bob nói rằng không sử dụng nhiều hơn 3 params để tôi giải quyết vấn đề đó bằng cách sử dụng các biến toàn cục phải không? :-) Tôi nghĩ rằng có khả năng tác giả không biết có nhiều cách tốt hơn để giải quyết vấn đề này - như được đề cập trong các câu trả lời dưới đây.
bytedev

9
Không quá n tham số là quy tắc ngón tay cái (với bất kỳ giá trị nào của n), không được khắc trên kim cương. Đừng nhầm lẫn lời khuyên tốt cho một nhiệm vụ. Rất nhiều tham số nói chung là một mùi mã mà bạn đã có quá nhiều trong một hàm / phương thức. Mọi người thường sử dụng để tránh chia thành nhiều chức năng để tránh các chi phí bổ sung của các cuộc gọi thêm. Rất ít ứng dụng này hoàn toàn chuyên sâu nữa và một trình hồ sơ có thể cho bạn biết khi nào và ở đâu bạn cần tránh các cuộc gọi thêm.
Jared Smith

14
Điều này cho thấy có gì sai với loại quy tắc không phán xét này: nó mở ra cánh cửa cho 'giải pháp' không phán xét. Nếu một hàm có nhiều đối số, nó có thể chỉ ra một thiết kế dưới mức tối ưu, thường không chỉ của hàm, mà cả bối cảnh mà nó đang được sử dụng. Giải pháp (nếu cần) là tìm cách cấu trúc lại mã. Tôi không thể cung cấp cho bạn một quy tắc đơn giản, chung chung, không phán xét về cách thực hiện, nhưng điều đó không có nghĩa là "không nhiều hơn N đối số" là một quy tắc tốt.
sdenham

4
Nếu bạn có quá nhiều tham số cho một hàm, tỷ lệ cược là một số trong số chúng có liên quan và nên được nhóm lại thành một đối tượng để sau đó trở thành một tham số duy nhất gói gọn nhiều mẩu dữ liệu. Có một lựa chọn thứ ba ở đây.

Câu trả lời:


113

Tôi không chia sẻ ý kiến ​​của bạn. Theo tôi, sử dụng các biến toàn cục là một thực tiễn tồi tệ hơn nhiều tham số bất kể các phẩm chất bạn mô tả. Lý do của tôi là nhiều tham số có thể làm cho một phương thức khó hiểu hơn, nhưng các biến toàn cục có thể gây ra nhiều vấn đề cho mã bao gồm khả năng kiểm tra kém, lỗi đồng thời và khớp nối chặt chẽ. Cho dù hàm có bao nhiêu tham số, nó sẽ không có vấn đề giống như các biến toàn cục.

... các biến tương tự được truyền dưới dạng tham số

có thể là một mùi thiết kế. Nếu bạn có cùng tham số được truyền cho hầu hết các chức năng trong hệ thống của mình, có thể có một mối quan tâm xuyên suốt cần được xử lý bằng cách giới thiệu một thành phần mới. Tôi không nghĩ việc chuyển cùng một biến cho nhiều hàm là lý do hợp lý để giới thiệu các biến toàn cục.

Trong một lần chỉnh sửa câu hỏi của bạn, bạn đã chỉ ra rằng việc giới thiệu các biến toàn cục có thể cải thiện khả năng đọc mã. Tôi không đồng ý. Việc sử dụng các biến toàn cục được ẩn trong mã thực hiện trong khi các tham số hàm được khai báo trong chữ ký. Các chức năng nên lý tưởng là tinh khiết. Họ chỉ nên hoạt động trên các tham số của họ và không nên có bất kỳ tác dụng phụ. Nếu bạn có một hàm thuần túy, bạn có thể suy luận về hàm này bằng cách chỉ nhìn vào một hàm. Nếu chức năng của bạn không thuần túy, bạn phải xem xét trạng thái của các thành phần khác và việc giải thích trở nên khó khăn hơn nhiều.


Ok, thật tốt khi nghe ý kiến ​​khác, nhưng về mùi thiết kế , tôi đang lập trình trong các vấn đề C được giải quyết bằng phương pháp trí tuệ nhân tạo và tôi có xu hướng sử dụng nhiều hàm hầu như luôn sử dụng cùng ma trận, mảng hoặc biến (mà Tôi chuyển dưới dạng tham số cho các hàm), tôi nói điều này bởi vì tôi không cảm thấy rằng tôi có thể đặt các biến này trong một khái niệm / thứ chung như cấu trúc hoặc liên kết nên tôi sẽ không biết cách tạo ra một thiết kế tốt hơn, Vì vậy, đó là lý do tại sao tôi nghĩ rằng việc sử dụng các biến toàn cầu trong trường hợp này có thể có giá trị, nhưng rất có thể tôi đã sai.
OiciTrap

1
Điều đó không giống như một vấn đề thiết kế. Tôi vẫn nghĩ việc truyền tham số cho các chức năng là thiết kế tốt nhất. Trong một hệ thống AI như bạn mô tả, tôi sẽ thấy hữu ích khi viết các bài kiểm tra đơn vị để kiểm tra các phần của hệ thống và cách dễ nhất để làm điều đó là với các tham số.
Samuel

96
Nhiều tham số làm cho chương trình con khó hiểu hơn, các biến toàn cục làm cho toàn bộ chương trình, tức là tất cả các chương trình con khó hiểu hơn.
Jörg W Mittag

2
Tôi duy trì một cơ sở mã trong đó một số hàm có hơn một chục tham số. Đó là một công cụ xử lý thời gian khổng lồ - mỗi lần tôi cần gọi hàm tôi cần mở tệp đó trong một cửa sổ khác để tôi biết các tham số cần được chỉ định theo thứ tự nào. Nếu tôi sử dụng một IDE mang lại cho tôi thứ gì đó như intellisense hoặc nếu tôi sử dụng một ngôn ngữ có tên tham số thì nó sẽ không tệ lắm nhưng ai có thể nhớ thứ tự hàng tá tham số cho tất cả các chức năng đó là gì?
Jerry Jeremiah

6
Câu trả lời là chính xác trong những gì nó nói, tuy nhiên có vẻ như OP hiểu sai về các khuyến nghị trong "Mã sạch" là điều hiển nhiên. Tôi chắc chắn không có khuyến nghị nào để thay thế các tham số chức năng theo toàn cầu trong cuốn sách đó.
Doc Brown

68

Bạn nên tránh các biến toàn cầu như bệnh dịch hạch .

Tôi sẽ không đặt một giới hạn cứng để số đối số (như 3 hoặc 4), nhưng bạn làm muốn giữ chúng ở mức tối thiểu, nếu có thể.

Sử dụng structs (hoặc các đối tượng trong C ++) để nhóm các biến lại thành một thực thể duy nhất và chuyển nó (bằng cách tham chiếu) cho các hàm. Thông thường, một hàm sẽ có một cấu trúc hoặc đối tượng (với một vài thứ khác nhau) được truyền cho nó cùng với một vài tham số khác cho biết hàm sẽ làm gì đó với struct.

Để có mùi thơm, sạch sẽ, mã mô-đun, hãy cố gắng tuân thủ nguyên tắc trách nhiệm duy nhất . Làm điều đó với các cấu trúc (hoặc đối tượng) của bạn, các hàm và các tệp nguồn. Nếu bạn làm điều đó, số lượng tham số tự nhiên được truyền cho một hàm sẽ rõ ràng.


5
Sự khác biệt chính giữa việc truyền hàng chục tham số ẩn trong một cấu trúc và truyền chúng rõ ràng là gì?
Ruslan

21
@Ruslan Sự gắn kết.
abuzittin gillifirca

9
Và bạn có nhiều khả năng cấu trúc lại hàm thành các hàm nhỏ hơn, vì bạn chỉ có thể chuyển một tham số cho các hàm phụ thay vì hàng chục tham số. Và ít rủi ro hơn khi trộn lẫn các tham số nếu bạn sử dụng các đối số vị trí.
Hans Olsson

8
Điều đó tốt, nhưng bạn phải đảm bảo sự gắn kết trong các Cấu trúc - đảm bảo rằng các tham số được nhóm thành một Cấu trúc có 'liên quan'. Bạn có thể sử dụng nhiều hơn một Struct trong một số trường hợp.
Andrew Dodds

8
@abuzmitillifirca Bạn không nhận được sự gắn kết tự động. Nếu sự biện minh duy nhất cho việc đưa các tham số trong một cấu trúc là chuyển chúng đến một chức năng cụ thể, thì sự gắn kết có lẽ là ảo tưởng.
sdenham

55

Chúng ta đang nói về tải nhận thức, không phải cú pháp. Vì vậy, câu hỏi là ... gì một tham số trong bối cảnh này?

Tham số là một giá trị ảnh hưởng đến hành vi của hàm. Càng nhiều tham số, bạn càng nhận được nhiều kết hợp giá trị, lý do về chức năng càng khó.

Theo nghĩa đó, các biến toàn cục mà hàm sử dụng các tham số. Chúng là các tham số không xuất hiện trong chữ ký của nó, có các vấn đề về trật tự xây dựng, kiểm soát truy cập và phần còn lại.

Trừ khi tham số được nói là cái được gọi là mối quan tâm xuyên suốt , đó là trạng thái toàn chương trình mà mọi thứ sử dụng nhưng không có gì thay đổi (ví dụ: đối tượng ghi nhật ký), bạn không nên thay thế tham số hàm bằng biến toàn cục. Chúng vẫn là các tham số, nhưng nhanh hơn.


11
Đối với bạn là +1, có thể là nhà vệ sinh hoặc nơi bắt đầu giống nhau. Công việc tốt đẹp chỉ ra con sói trong quần áo cừu.
Jared Smith

1
+1 cho biết cả hai parms và vars toàn cầu đều xấu. Nhưng tôi muốn làm rõ một cái gì đó. Trong hầu hết các ngôn ngữ, các tham số nguyên thủy được truyền theo giá trị theo mặc định (Java) và trong các ngôn ngữ khác, bạn có thể chuyển chúng theo giá trị một cách rõ ràng (PL / SQL). Mặt khác, các nguyên thủy toàn cầu luôn được truy cập bằng cách tham chiếu (có thể nói). Vì vậy, các tham số, ít nhất là các kiểu nguyên thủy, luôn an toàn hơn các biến toàn cục. Mặc dù tất nhiên có nhiều hơn hai hoặc ba tham số là một mùi, và có mười hai tham số là một mùi rất lớn mà shoule được tái cấu trúc.
Tulains Córdova

4
Hoàn toàn, một biến toàn cục là một tham số ẩn.
Bill K

+1 Theo quan điểm của bạn, tôi đã thấy các mô phỏng MATLAB dựa trên các biến toàn cục để truyền dữ liệu. Kết quả hoàn toàn không thể đọc được vì rất khó để biết biến nào là tham số cho hàm nào.
Cort Ammon

34

IMHO câu hỏi của bạn dựa trên một sự hiểu lầm. Trong "Clean Code", Bob Martin không đề xuất thay thế các tham số chức năng lặp đi lặp lại bởi toàn cầu, đó sẽ là một lời khuyên thực sự khủng khiếp. Ông đề nghị thay thế chúng bằng các biến thành viên riêng của lớp hàm. Và ông cũng đề xuất các lớp nhỏ, gắn kết (thường nhỏ hơn 600 dòng mã bạn đã đề cập), vì vậy các biến thành viên này chắc chắn không có toàn cục.

Vì vậy, khi bạn có ý kiến ​​trong một bối cảnh có ít hơn 600 dòng "sử dụng các biến toàn cục sẽ có giá trị" , thì bạn hoàn toàn chia sẻ ý kiến ​​của chú Bob. Tất nhiên, thật đáng tranh luận nếu "tối đa 3 tham số" là con số lý tưởng và nếu quy tắc này đôi khi dẫn đến quá nhiều biến thành viên ngay cả trong các lớp nhỏ. IMHO đây là một sự đánh đổi, không có quy tắc khó và nhanh chóng để vẽ đường.


10
Tôi chưa bao giờ hiểu lý do tại sao một người nào đó muốn làm cho lớp của họ trở nên trạng thái bằng cách nhồi các tham số vào một hàm tạo thay vì chỉ sống với một đối số thực tế. Điều này luôn luôn gây ấn tượng với tôi như một sự gia tăng lớn về độ phức tạp. (Một ví dụ thực tế mà tôi đã thấy đây là một đối tượng kết nối cơ sở dữ liệu, điều này khiến cho việc cố gắng theo dõi trạng thái của cơ sở dữ liệu thông qua chương trình gần như không thể khi kết hợp với việc tiêm phụ thuộc.) Nhưng có lẽ Clean Code có nhiều điều để nói về điều đó môn học. Globals, tất nhiên, là một lựa chọn thậm chí còn tồi tệ hơn liên quan đến việc làm cho mọi thứ trở nên có trạng thái.
jpmc26

2
@ jpmc26: người ta chỉ nhận được "sự gia tăng phức tạp" nếu các lớp trở nên quá lớn và có quá nhiều biến thành viên, do đó kết quả không còn gắn kết nữa.
Doc Brown

4
Tôi nghĩ rằng phản hồi đó bỏ qua những khó khăn trong việc quản lý nhà nước (thậm chí có thể thay đổi), điều đó trải rộng trên nhiều lớp. Khi một hàm không chỉ phụ thuộc vào các đối số mà còn phụ thuộc vào cách đối tượng được xây dựng (hoặc thậm chí được sửa đổi trong suốt vòng đời của nó), việc hiểu trạng thái hiện tại của nó khi bạn thực hiện một cuộc gọi cụ thể trở nên khó khăn hơn. Bây giờ bạn phải theo dõi quá trình xây dựng của một đối tượng khác , để tìm ra cuộc gọi sẽ làm gì. Thêm các biến thể hiện tích cực làm tăng lượng trạng thái của chương trình, trừ khi bạn xây dựng đối tượng và ngay lập tức vứt nó đi?
jpmc26

3
@ jpmc26 Một mẫu tôi sử dụng thường xuyên khi tái cấu trúc là hàm tạo hoạt động như đặt bối cảnh, sau đó các đối số phương thức dành riêng cho một hành động. Đối tượng không chính xác trạng thái, bởi vì trạng thái mà nó giữ không bao giờ thay đổi, nhưng việc chuyển các hành động phổ biến đó sang các phương thức của bộ chứa này sẽ cải thiện đáng kể khả năng đọc khi sử dụng (bối cảnh chỉ được đặt một lần, gần giống với trình quản lý bối cảnh của python) và giảm trùng lặp nếu nhiều cuộc gọi được thực hiện cho các phương thức của đối tượng.
Izkata

3
+1 Để nói rõ rằng các biến thành viên không phải là biến toàn cục. Nhiều người nghĩ rằng họ là.
Tulains Córdova

34

Có nhiều tham số được coi là không mong muốn, nhưng biến chúng thành các trường hoặc biến toàn cục thì tệ hơn rất nhiều vì nó không giải quyết được vấn đề thực tế mà chỉ đưa ra các vấn đề mới.

Có nhiều tham số không phải là vấn đề, nhưng đó là một triệu chứng mà bạn có thể gặp vấn đề. Hãy xem xét phương pháp này:

Graphics.PaintRectangle(left, top, length, height, red, green, blue, transparency);

Có 7 tham số là một dấu hiệu cảnh báo xác định. Vấn đề của underling là các tham số này không độc lập mà thuộc về các nhóm. lefttopthuộc về nhau như một Positioncấu trúc, lengthheightnhư một Sizecấu trúc, và red, bluegreennhư một Colorcấu trúc. Và có lẽ Colorvà minh bạch thuộc về một Brushcấu trúc? Có lẽ PositionSizethuộc về nhau trong một Rectanglecấu trúc, trong trường hợp nào chúng ta thậm chí có thể xem xét biến nó thành một Paintphương thức trên Rectangleđối tượng thay thế? Vì vậy, chúng tôi có thể kết thúc với:

Rectangle.Paint(brush);

Nhiệm vụ đã hoàn thành! Nhưng điều quan trọng là chúng tôi thực sự đã cải thiện thiết kế tổng thể, và việc giảm số lượng tham số là hệ quả của việc này. Nếu chúng ta chỉ giảm số lượng tham số mà không giải quyết các vấn đề tiềm ẩn, chúng ta có thể làm một cái gì đó như thế này:

Graphics.left = something;
Graphics.top = something;
Graphics.length = something;
...etc
Graphics.PaintRectangle();

Ở đây chúng tôi đã đạt được mức giảm tương tự về số lượng tham số, nhưng chúng tôi thực sự đã làm cho thiết kế tồi tệ hơn .

Điểm mấu chốt: Đối với bất kỳ lời khuyên lập trình và quy tắc ngón tay cái nào, điều thực sự quan trọng là phải hiểu lý do cơ bản.


4
+1 câu trả lời hay, mang tính xây dựng, dễ hiểu, không lý thuyết.
AnoE

1
Chưa kể, cái quái gì là "hình vuông" của bạn khi có cả thuộc tính chiều dài VÀ chiều cao. :)
tự đại diện

1
+1 để thừa nhận rằng cách thứ ba rõ ràng ngụ ý bởi một số câu trả lời (nghĩa là nhiều bài tập cho một số cấu trúc / đối tượng trước khi gọi hàm) không tốt hơn.
benxyzzy

@Wildcard: Cảm ơn, đã đổi nó thành "hình chữ nhật" để tránh nhầm lẫn vấn đề!
JacquesB

7

Có đáng để sử dụng biến toàn cục để giảm số lượng tham số của hàm hay không?

không phải

Tôi đọc những chương đầu tiên của cuốn sách này

Bạn đã đọc phần còn lại của cuốn sách?

Toàn cầu chỉ là một tham số ẩn. Chúng gây ra một nỗi đau khác nhau. Nhưng nó vẫn đau. Ngừng suy nghĩ các cách để có được xung quanh quy tắc này. Hãy suy nghĩ về cách làm theo nó.

Một tham số là gì?

Đó là công cụ. Trong một hộp được dán nhãn độc đáo. Tại sao bạn có bao nhiêu hộp khi bạn có thể đặt bất cứ thứ gì vào đó?

Đó là chi phí vận chuyển và xử lý.

Move(1, 2, 3, 4)

Nói cho tôi bạn có thể đọc nó. Tiếp tục, cố gắng.

Move(PointA, PointB)

Đó là lý do tại sao.

Thủ thuật đó được gọi là giới thiệu đối tượng tham số .

Và đúng, đó chỉ là một mẹo nếu tất cả những gì bạn đang làm là đếm các tham số. Những gì bạn nên đếm là Ý TƯỞNG! Trừu tượng! Bao nhiêu bạn đang làm cho tôi nghĩ về cùng một lúc? Giữ cho nó đơn giản.

Bây giờ đây là cùng một tính:

Move(xyx, y)

SỞ HỮU! Thật kinh khủng! Điều gì đã xảy ra ở đây?

Nó không đủ để giới hạn số lượng ý tưởng. Họ phải là những ý tưởng rõ ràng. Xyx là cái quái gì vậy?

Bây giờ điều này vẫn còn yếu. Cách nào mạnh mẽ hơn để nghĩ về điều này?

Chức năng nên nhỏ. Không nhỏ hơn thế.

Chú Bob

Move(PointB)

Tại sao làm cho chức năng làm nhiều hơn nó thực sự cần phải làm? Nguyên tắc trách nhiệm duy nhất không chỉ dành cho các lớp. Nghiêm túc mà nói, đáng để thay đổi toàn bộ kiến ​​trúc chỉ để ngăn một chức năng biến thành cơn ác mộng quá tải với 10 tham số đôi khi liên quan đến một số tham số không thể sử dụng với các chức năng khác.

Tôi đã thấy mã trong đó số dòng phổ biến nhất trong một hàm là 1. Nghiêm túc. Tôi không nói rằng bạn phải viết theo cách đó nhưng sheesh, đừng nói với tôi rằng toàn cầu là cách DUY NHẤT bạn có thể tuân thủ quy tắc này. Ngừng cố gắng thoát khỏi tái cấu trúc chức năng đó đúng cách. Bạn biết bạn có thể. Nó có thể chia thành một vài chức năng. Nó thực sự có thể biến thành một vài đối tượng. Địa ngục bạn thậm chí có thể phá vỡ một phần của nó thành một ứng dụng hoàn toàn khác.

Cuốn sách không nói cho bạn biết các thông số của bạn. Nó bảo bạn chú ý đến nỗi đau mà bạn gây ra. Bất cứ điều gì khắc phục nỗi đau đều khắc phục vấn đề. Chỉ cần lưu ý khi bạn chỉ đơn giản là đánh đổi nỗi đau này sang nỗi đau khác.


3
"Bạn đã đọc phần còn lại của cuốn sách?" Câu hỏi của bạn đã được trả lời trong 8 từ đầu tiên của bài đăng của tôi ...
OiciTrap

Tôi hoàn toàn đồng ý - vấn đề là phân tách vấn đề thành những mảnh nhỏ. Các đối tượng thực sự có thể giúp tổ chức các phần này và nhóm chúng lại, chúng cũng cho phép một đơn vị khái niệm duy nhất được truyền dưới dạng tham số thay vì một loạt các phần không được kết nối. Tôi bị rối loạn khi thấy một phương thức có nhiều hơn 3 tham số. 5 là một dấu hiệu cho thấy thiết kế của tôi đã bị hỏng và tôi cần một vòng tái cấu trúc khác. Cách tốt nhất mà tôi đã tìm thấy để giải quyết các vấn đề thiết kế như đếm tham số là chỉ cần cấu trúc lại mọi thứ thành các đơn vị (lớp / phương thức) nhỏ hơn, đơn giản hơn.
Bill K

2
Giọng điệu của câu trả lời này có thể được cải thiện. Nó đọc như rất đột ngột và khắc nghiệt. Ví dụ: "Hãy cho tôi biết bạn có thể đọc nó. Tiếp tục, thử." có vẻ rất tích cực và có thể được viết lại thành "Trong hai lệnh gọi hàm trên / dưới, cái nào dễ đọc hơn?" Bạn nên cố gắng để có được điểm qua mà không có sự xâm lược. OP chỉ đang cố gắng học hỏi.
Kyle A

Đừng quên OP cũng đang cố gắng tỉnh táo.
candied_orange

4

Tôi sẽ không bao giờ sử dụng các biến toàn cục để giảm tham số. Lý do là các biến toàn cục có thể bị thay đổi bởi bất kỳ hàm / lệnh nào, do đó làm cho đầu vào hàm không đáng tin cậy và dễ bị các giá trị nằm ngoài phạm vi của hàm có thể xử lý. Điều gì xảy ra nếu biến được thay đổi trong quá trình thực thi hàm và một nửa hàm có các giá trị khác với nửa còn lại?

Mặt khác, việc truyền tham số, giới hạn phạm vi của biến chỉ với chức năng của chính nó để chỉ có chức năng có thể sửa đổi một tham số một khi được gọi.

Nếu bạn cần truyền các biến toàn cục thay vì tham số, tốt nhất nên thiết kế lại mã.

Chỉ hai xu của tôi.


"Tôi sẽ không bao giờ sử dụng các biến toàn cục để giảm tham số" hoàn toàn đồng ý. Nó tạo ra khớp nối không cần thiết.
bytedev

2

Tôi với chú Bob về điều này và đồng ý rằng hơn 3 thông số là điều cần tránh (tôi rất hiếm khi sử dụng nhiều hơn 3 thông số trong một chức năng). Có nhiều thông số trên một chức năng duy nhất tạo ra vấn đề bảo trì lớn hơn và có thể là mùi mà chức năng của bạn đang làm quá nhiều / có quá nhiều trách nhiệm.

Nếu bạn đang sử dụng nhiều hơn 3 trong một phương thức trong ngôn ngữ OO thì bạn nên xem xét các tham số không liên quan với nhau theo một cách nào đó và do đó bạn thực sự nên truyền vào một đối tượng?

Ngoài ra, nếu bạn tạo nhiều chức năng (nhỏ hơn), bạn cũng sẽ nhận thấy rằng các chức năng thường có 3 thông số trở xuống. Trích xuất hàm / phương thức là bạn của bạn :-).

Không sử dụng các biến toàn cục như một cách để có được vòng có nhiều thông số hơn! Đó là trao đổi một thực hành xấu cho một thậm chí còn tồi tệ hơn!


1

Một thay thế hợp lệ cho nhiều tham số chức năng là để giới thiệu một đối tượng tham số . Này rất hữu ích nếu bạn có một sáng tác phương pháp mà đi (gần như) tất cả các thông số của mình cho một loạt các phương pháp khác.

Trong các trường hợp đơn giản, đây là một DTO đơn giản không có gì ngoài các tham số cũ làm thuộc tính.


1

Sử dụng các biến toàn cục luôn có vẻ là một cách dễ dàng để mã hóa (đặc biệt là trong một chương trình nhỏ), nhưng nó sẽ làm cho mã của bạn khó mở rộng.

Có, bạn có thể giảm số lượng tham số trong hàm bằng cách sử dụng một mảng để liên kết các tham số trong một thực thể.

function <functionname>(var1,var2,var3,var4.....var(n)){}

Hàm trên sẽ được chỉnh sửa và thay đổi thành [sử dụng mảng kết hợp] -

data=array(var1->var1,
           var2->var2
           var3->var3..
           .....
           ); // data is an associative array

function <functionname>(data)

Tôi đồng ý với câu trả lời của robert bristow-johnson : bạn thậm chí có thể sử dụng một cấu trúc để liên kết dữ liệu trong một thực thể duy nhất.


1

Lấy một ví dụ từ PHP 4, hãy xem chữ ký hàm cho mktime():

  • int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )

Bạn không thấy khó hiểu sao? Hàm được gọi là "tạo thời gian" nhưng phải mất các tham số ngày, tháng và năm cũng như ba tham số thời gian. Làm thế nào dễ dàng để nhớ thứ tự họ đi theo? Nếu bạn nhìn thấy mktime(1, 2, 3, 4, 5, 2246);thì sao? Bạn có thể hiểu rằng mà không cần phải tham khảo bất cứ điều gì khác? Được 2246hiểu là thời gian 24 giờ "22:46"? Các thông số khác có nghĩa là gì? Nó sẽ tốt hơn như là một đối tượng.

Chuyển sang PHP 5, bây giờ có một đối tượng DateTime. Trong số các phương pháp của nó là hai được gọi setDate()setTime(). Chữ ký của họ như sau:

  • public DateTime setDate ( int $year , int $month , int $day )
  • public DateTime setTime ( int $hour , int $minute [, int $second = 0 ] )

Bạn vẫn phải nhớ rằng thứ tự của các tham số đi từ lớn nhất đến nhỏ nhất, nhưng đó là một cải tiến lớn. Lưu ý rằng không có một phương thức nào cho phép bạn đặt tất cả sáu tham số cùng một lúc. Bạn phải thực hiện hai cuộc gọi riêng biệt để làm điều này.

Điều mà chú Bob đang nói là tránh có cấu trúc phẳng. Các tham số liên quan nên được nhóm lại thành một đối tượng và nếu bạn có nhiều hơn ba tham số, rất có thể bạn đã có một đối tượng giả ở đó, điều này cho bạn cơ hội tạo một đối tượng thích hợp để phân tách rõ hơn. Mặc dù PHP không có một lớp DateTimelớp riêng biệt , bạn có thể xem xét điều đó DateTimethực sự có chứa một Dateđối tượng và một Timeđối tượng.

Bạn có thể có cấu trúc như sau:

<?php
$my_date = new Date;
$my_date->setDay(5);
$my_date->setMonth(4);
$my_date->setYear(2246);

$my_time = new Time;
$my_time->setHour(1);
$my_time->setMinute(2);
$my_time->setSecond(3);

$my_date_time = new DateTime;
$my_date_time->setTime($my_time);
$my_date_time->setDate($my_date);
?>

Có bắt buộc phải đặt hai hoặc ba tham số mỗi lần không? Nếu bạn muốn thay đổi chỉ theo giờ hoặc chỉ trong ngày, giờ đây thật dễ dàng để làm điều đó. Đúng, đối tượng cần được xác nhận để đảm bảo mỗi tham số hoạt động với các tham số khác, nhưng dù sao đó cũng là trường hợp trước đó.

Điều quan trọng nhất là, có dễ hiểu hơn không, và do đó duy trì? Khối mã ở phía dưới lớn hơn một mktime()hàm, nhưng tôi cho rằng điều đó dễ hiểu hơn nhiều; ngay cả một người không lập trình cũng sẽ không gặp nhiều khó khăn khi làm việc đó. Mục tiêu không phải luôn luôn là mã ngắn hơn hoặc mã thông minh hơn, mà là mã dễ bảo trì hơn.

Ồ, và đừng sử dụng toàn cầu!


1

Rất nhiều câu trả lời tốt ở đây nhưng hầu hết không giải quyết được vấn đề. Tại sao những quy tắc này? Đó là về phạm vi, đó là về sự phụ thuộc và đó là về mô hình thích hợp.

Globals cho tranh luận là tồi tệ hơn bởi vì nó chỉ trông giống như bạn làm cho nó đơn giản hơn nhưng thực tế bạn chỉ che giấu sự phức tạp. Bạn không nhìn thấy nó nữa trong nguyên mẫu nhưng bạn vẫn phải nhận thức được nó (điều này rất khó vì bạn không còn thấy nữa) và việc tìm hiểu về logic của hàm sẽ không giúp bạn vì có thể là logic ẩn khác can thiệp sau lưng của bạn. Phạm vi của bạn đã đi khắp mọi nơi và bạn đã giới thiệu một sự phụ thuộc vào bất cứ điều gì bởi vì bất cứ điều gì bây giờ có thể gây rối với biến của bạn. Không tốt.

Điều chính để duy trì cho một chức năng là bạn có thể hiểu những gì nó làm bằng cách nhìn vào nguyên mẫu và gọi. Vì vậy, tên nên rõ ràng và rõ ràng. Nhưng ngoài ra, càng có nhiều tranh luận thì càng khó nắm bắt những gì nó làm. Nó mở rộng phạm vi trong đầu bạn, quá nhiều thứ đang diễn ra, đây là lý do tại sao bạn muốn giới hạn số lượng. Nó quan trọng loại tranh luận mà bạn đang đối phó mặc dù, một số tồi tệ hơn so với những người khác. Một boolean tùy chọn bổ sung cho phép xử lý không phân biệt chữ hoa chữ thường không làm cho hàm khó hiểu hơn nên bạn sẽ không muốn thực hiện một vấn đề lớn về nó. Là một lưu ý phụ, enum tạo ra các đối số tốt hơn so với booleans vì ý nghĩa của enum là rõ ràng trong cuộc gọi.

Vấn đề điển hình không phải là bạn viết một hàm mới với số lượng đối số khổng lồ, bạn sẽ bắt đầu chỉ với một vài khi bạn không nhận ra vấn đề bạn đang giải quyết thực sự phức tạp đến mức nào. Khi chương trình của bạn phát triển, danh sách đối số dần dần có xu hướng dài hơn. Một khi một mô hình đã được thiết lập trong tâm trí của bạn, bạn muốn giữ nó bởi vì nó là một tài liệu tham khảo an toàn mà bạn biết. Nhưng nhìn lại mô hình có thể không tuyệt vời như vậy. Bạn đã bỏ lỡ một bước hoặc quá trong logic và bạn không thể nhận ra một hoặc hai thực thể. "OK ... Tôi có thể bắt đầu lại và dành một hoặc hai ngày để cấu trúc lại mã của mình hoặc ... Tôi có thể thêm đối số này để tôi có thể làm cho nó thực hiện đúng sau tất cả và được thực hiện với nó. . Để loại bỏ lỗi này ra khỏi đĩa của tôi để tôi có thể di chuyển ghi chú dán để thực hiện. "

Bạn càng thường xuyên đi với giải pháp thứ hai, việc bảo trì sẽ càng tốn kém hơn và một công cụ tái cấu trúc sẽ càng khó và không hấp dẫn.

Không có giải pháp tấm nồi hơi để giảm số lượng đối số trong một hàm hiện có. Chỉ cần nhóm chúng vào các hợp chất không thực sự làm cho mọi thứ dễ dàng hơn, nó chỉ là một cách khác để xóa sự phức tạp dưới thảm. Làm đúng bao gồm nhìn lại toàn bộ ngăn xếp cuộc gọi và nhận ra những gì còn thiếu hoặc đã được thực hiện sai.


0

Một vài lần tôi đã thấy rằng việc nhóm rất nhiều tham số được gửi cùng nhau cải thiện mọi thứ.

  • Nó buộc bạn phải đặt một cái tên hay cho sự gián đoạn các khái niệm được sử dụng cùng nhau. Nếu bạn sử dụng các tham số đó cùng nhau thì có thể chúng có mối quan hệ (hoặc bạn hoàn toàn không nên sử dụng cùng nhau).

  • Một lần với đối tượng tôi thường thấy rằng một số chức năng có thể được di chuyển mà đối tượng rõ ràng này là stuypid. Nó thường dễ dàng để kiểm tra và với sự gắn kết tuyệt vời và khớp nối thấp làm cho mọi thứ thậm chí còn tốt hơn.

  • Lần sau khi tôi cần thêm một tham số mới, tôi có một vị trí đẹp để bao gồm nó mà không thay đổi chữ ký của rất nhiều phương thức.

Vì vậy, nó có thể không hoạt động 100% lần nhưng hãy tự hỏi liệu danh sách tham số này có nên được nhóm trong một đối tượng không. Và làm ơn. Không sử dụng các lớp được đánh dấu như Tuple để tránh tạo đối tượng. Bạn đang sử dụng lập trình hướng đối tượng, đừng bận tâm để tạo thêm đối tượng nếu bạn cần chúng.


0

Với tất cả sự tôn trọng, tôi khá chắc chắn rằng bạn đã hoàn toàn bỏ lỡ quan điểm có một số lượng nhỏ các tham số trong một hàm.

Ý tưởng là bộ não chỉ có thể chứa rất nhiều "thông tin hoạt động" cùng một lúc và nếu bạn có n tham số trong một chức năng, bạn có thêm n phần "thông tin hoạt động" cần có trong não để dễ dàng và chính xác hiểu được đoạn mã đang làm gì (Steve McConnell, trong Code Complete (một cuốn sách hay hơn nhiều, IMO), nói điều gì đó tương tự về 7 biến trong cơ thể của một phương thức: hiếm khi chúng ta đạt được điều đó, nhưng bất kỳ điều gì nữa và bạn sẽ mất đi khả năng giữ mọi thứ thẳng trong đầu của bạn).

Điểm của số lượng biến thấp là có thể giữ các yêu cầu nhận thức khi làm việc với mã này nhỏ, do đó bạn có thể làm việc với nó (hoặc đọc nó) hiệu quả hơn. Một nguyên nhân phụ của điều này là mã được bao bọc kỹ lưỡng sẽ có xu hướng ngày càng ít tham số (ví dụ, mã được bao bọc kém có xu hướng nhóm một loạt các thứ thành một mớ hỗn độn).

Bằng cách chuyển các đối tượng thay vì các giá trị, có lẽ bạn đạt được mức độ trừu tượng cho bộ não của mình bởi vì bây giờ nó cần nhận ra có, tôi đã có SearchContext để làm việc ở đây thay vì nghĩ về 15 thuộc tính có thể nằm trong bối cảnh tìm kiếm đó.

Bằng cách cố gắng sử dụng các biến toàn cầu, bạn đã hoàn toàn đi sai hướng. Bây giờ không chỉ bạn không giải quyết được các vấn đề về việc có quá nhiều tham số cho một hàm, bạn đã xử lý vấn đề đó và đưa nó vào một vấn đề tốt hơn rất nhiều mà bây giờ bạn phải mang theo trong đầu!

Bây giờ thay vì chỉ làm việc ở cấp độ chức năng, bạn cũng cần xem xét phạm vi toàn cầu của dự án của mình (gawd, thật khủng khiếp! Tôi rùng mình ...). Bạn thậm chí không có tất cả thông tin của mình trước hàm trong hàm (crap, tên biến toàn cầu đó là gì?) (Tôi hy vọng điều này không bị thay đổi bởi một cái gì khác kể từ khi tôi gọi hàm này).

Các biến có phạm vi toàn cầu là một trong những điều tồi tệ nhất để thấy trong một dự án (lớn hay nhỏ). Họ biểu thị một khuyết tật để quản lý phạm vi thích hợp, đó là một kỹ năng cơ bản cao để lập trình. Họ. Được. Quỷ dữ.

Bằng cách di chuyển các tham số ra khỏi chức năng của bạn và đưa chúng vào toàn cầu, bạn đã tự bắn vào chân mình (hoặc chân hoặc mặt). Và Chúa cấm bạn quyết định rằng , tôi có thể sử dụng lại toàn cầu này cho mục đích khác ... tâm trí tôi run rẩy khi nghĩ.

Toàn bộ lý tưởng là giữ cho mọi thứ dễ quản lý và các biến toàn cục sẽ KHÔNG làm điều đó. Tôi đã đi xa để nói rằng họ là một trong những điều tồi tệ nhất bạn có thể làm để đi theo hướng ngược lại.


-1

Tôi đã tìm thấy một cách tiếp cận hiệu quả cao (bằng JavaScript) để giảm thiểu ma sát giữa các giao diện: Sử dụng giao diện thống nhất cho tất cả các mô-đun , cụ thể: các hàm param duy nhất.

Khi bạn cần nhiều tham số: Sử dụng một Object / Hash hoặc Array.

Chịu đựng tôi, tôi hứa tôi sẽ không troll ...

Trước khi bạn nói, những gì tốt là một thông số duy nhất? Một số hay khác nhau Có một sự khác biệt giữa 1 Array và nhiều arg funcs?

Vâng, vâng. Nó có thể trực quan tinh tế, nhưng sự khác biệt là nhiều lần - tôi khám phá nhiều lợi ích ở đây

Rõ ràng một số ppl nghĩ rằng 3 là # đúng của các đối số. Một số người nghĩ rằng đó là 2. Chà, điều đó vẫn đặt ra câu hỏi, "param nào đi theo arg [0]?" Thay vì chọn tùy chọn ràng buộc giao diện với khai báo cứng nhắc hơn.

Tôi đoán tôi tranh luận cho một vị trí cấp tiến hơn: đừng dựa vào lập luận theo vị trí. Tôi chỉ cảm thấy nó mong manh và dẫn đến tranh luận về vị trí của những cuộc tranh cãi chết tiệt. Bỏ qua nó và di chuyển ngay đến cuộc chiến không thể tránh khỏi về tên của các hàm và biến. 😉

Nghiêm túc mà nói, sau khi đặt tên ổn định, hy vọng bạn kết thúc với mã như sau, phần nào đó tự ghi lại, không nhạy cảm với vị trí và cho phép các thay đổi param trong tương lai được xử lý bên trong hàm:

function sendMessage({toUser, fromUser, subject, body}) { }

// And call the method like so:
sendMessage({toUser: this.parentUser, fromUser: this.currentUser, subject: ‘Example Alert’})


6
Làm cho các đối số được đặt tên không thực sự chỉ vượt qua một đối số.
JDługosz

Tại sao nó "giả mạo" nếu tôi đạt được mục tiêu mà tôi đặt ra? Tôi đang đặt ưu tiên cao hơn cho các đối số được đặt tên. Bởi vì các đối số vị trí không rõ ràng đối với việc gọi mã và với # các hàm được đặt tên, một nhà phát triển phải ghi nhớ nên việc ghi nhớ tham số nào ở đâu và tùy chọn nào là không hữu ích. ... Cuối cùng, bạn sẽ muốn thêm một thông số bắt buộc sau các tùy chọn, chúc may mắn và nâng cấp nhà thẻ đó.
Dan Levy

2
Các thông số được đặt tên cũng là một mẹo học tập củng cố - con người gắn nhiều ý nghĩa hơn vào các bộ sưu tập các từ.
Dan Levy
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.