Thực hành tốt nhất về thứ tự các tham số trong một chức năng là gì?


52

Đôi khi (hiếm khi), có vẻ như việc tạo ra một hàm cần một lượng tham số kha khá là con đường tốt nhất. Tuy nhiên, khi tôi làm, tôi cảm thấy như tôi thường chọn thứ tự các tham số một cách ngẫu nhiên. Tôi thường đi theo "thứ tự quan trọng", với tham số quan trọng nhất trước tiên.

Có cách nào tốt hơn để làm điều này? Có cách "thực hành tốt nhất" để đặt hàng các tham số giúp tăng cường sự rõ ràng không?


5
Các tham số được đặt tên làm cho điều này ít hơn một vấn đề. Python đưa nó đến cùng cực, nhìn vào nó. Một ví dụ điển hình là trong C # - nhiều cách để gọi MessageBox.Show. Nhìn vào đó là tốt.
Công việc

8
Trong Haskell, tính hữu dụng có thể có của ứng dụng hàm một phần thường gợi ý thứ tự đối số tự nhiên.
tdammers

Những gì bạn sẽ xem xét một số lượng lớn các tham số?
Chris

Tôi đã suy nghĩ> 2. Mặc dù tôi đoán việc đặt hàng áp dụng cho 2 tham số giống nhau.
Casey Patton

3
@tdammers điều này cũng đúng với bất kỳ ngôn ngữ nào có hỗ trợ trực tiếp cho món cà ri
jk.

Câu trả lời:


55

Nói chung: sử dụng nó .

Viết một bài kiểm tra cho chức năng của bạn, một bài kiểm tra thế giới thực.
Một cái gì đó bạn thực sự muốn làm với chức năng đó .

Và xem theo thứ tự bạn đã đặt những thứ đó xuống.

Trừ khi bạn đã có (hoặc biết) một số chức năng làm điều gì đó tương tự.
Trong trường hợp đó: phù hợp với những gì họ đã làm, ít nhất là cho các đối số đầu tiên.

ví dụ: Có phải tất cả đều lấy tài liệu / đối tượng / tệp con trỏ / chuỗi giá trị / tọa độ làm (các) đối số đầu tiên không? Vì lợi ích của Chúa phù hợp với những lập luận đó .

Tránh nhầm lẫn đồng nghiệpbản thân tương lai của bạn .


12
"Tránh nhầm lẫn ... bản thân tương lai của bạn" nghe có vẻ như là một triết lý tốt nói chung.
Jeanne Pindar

28

Tôi thường đi với các quy tắc này, mặc dù không phải lúc nào cũng có cùng một ưu tiên. Tôi đoán bây giờ nó là một quá trình suy nghĩ tự động và tôi không nghĩ quá nhiều, ngoại trừ thiết kế API công khai .

Kênh lựa chọn

  1. Ngữ nghĩa
  2. Tầm quan trọng / sự liên quan
  3. Tần suất sử dụng
  4. Mối quan tâm I / O

1. Ngữ nghĩa đầu tiên

Đặc biệt là trong OOP, chọn tham số dựa trên ý nghĩa ngữ nghĩa của chúng đối với hành động hoặc thông báo. Chữ ký của một phương thức được đặt tên tốt với một tham số được đặt tên tốt nên:

  • cảm thấy tự nhiên để gọi
  • được tự mô tả về ý định và hành vi.

(Vì những lý do này, đôi khi sử dụng các loại tùy chỉnh hoặc bí danh thay vì nguyên thủy có thể làm tăng tính biểu cảm của chữ ký của bạn.)

2. Sau đó, Tầm quan trọng

Tham số "đáng kể" nhất đến trước (hoặc tiếp theo ...)

3. Sau đó tần số

Tần số cũng quan trọng, đặc biệt là trong ngôn ngữ mà bạn không đặt tên tham số nhưng có thể có giá trị mặc định trên tham số vị trí. Điều đó ngụ ý rằng thứ tự của các tham số không thay đổi và rõ ràng là bạn không thể đặt tham số N + 1 nếu bạn muốn buộc giá trị mặc định của tham số Nth (ngoại trừ nếu ngôn ngữ của bạn có khái niệm về tham số giữ chỗ ).

Tin tốt cho bạn là thông thường, tần suất liên quan đến tầm quan trọng, do đó đi đôi với điểm trước. Và sau đó, có thể tùy thuộc vào bạn để tạo API của mình để có ngữ nghĩa phù hợp.

4. Đừng quên I / O

nếu phương thức / hàm của bạn nhận một số đầu vào và tạo ra một đầu ra và cái sau không được "trả lại" (thông qua câu lệnh trả về) hoặc "ném" (sử dụng một hệ thống ngoại lệ), thì bạn sẽ có tùy chọn để vượt qua giá trị trở lại cho người gọi bằng các tham số khác của bạn (hoặc tham số đầu vào). Điều đó liên quan đến ngữ nghĩa và trong hầu hết các trường hợp, sẽ có ý nghĩa khi có các tham số đầu tiên xác định đầu ra và các tham số cuối cùng nhận đầu ra.

Ngoài ra, một cách tiếp cận khác để có ít tham số hơn và tối đa hóa ngữ nghĩa sẽ là sử dụng cách tiếp cận chức năng hoặc để xác định mẫu Builder , để bạn có thể xếp chồng rõ ràng đầu vào, xác định đầu ra và truy xuất chúng khi cần.

(Lưu ý tôi không đề cập đến các biến toàn cục, vì tại sao bạn sẽ sử dụng một biến, phải không?)


Một số điều cần xem xét

  • Khả năng sử dụng

    Hầu hết những điều trên sẽ hiển thị một cách tự nhiên nếu bạn làm theo lời khuyên của ZJR : Sử dụng nó!

  • Xem xét tái cấu trúc

    Nếu bạn lo lắng về việc đặt hàng tham số, có thể sự lo lắng này tìm thấy gốc rễ của nó ở trên và trong thực tế là API của bạn được thiết kế tồi. Nếu bạn có quá nhiều tham số, một cái gì đó rất có thể có thể được thành phần hóa / mô đun hóa và tái cấu trúc .

  • Xem xét hiệu suất

    Hãy nhớ rằng việc triển khai một số ngôn ngữ sẽ chịu các tác động rất quan trọng đến việc quản lý bộ nhớ thời gian chạy của bạn khi sử dụng các tham số. Do đó, lý do tại sao nhiều sách theo phong cách ngôn ngữ khuyên bạn nên giữ danh sách tham số đơn giản và ngắn gọn . Ở tối đa 4 tham số, ví dụ. Tôi để nó như một bài tập cho bạn để tìm hiểu tại sao.

  • Câu trả lời của Bevan và đề cập đến các khuyến nghị của Clean Code chắc chắn cũng có liên quan!


18

Tôi trân trọng gửi rằng lo lắng về thứ tự tham số là lo lắng về điều sai.

Trong cuốn sách " Mã sạch " của chú Bob, ông chủ trương, một cách thuyết phục, rằng các phương pháp không bao giờ nên có nhiều hơn hai đối số - và hầu hết chỉ nên có một, nếu có. Khi đây là trường hợp, đặt hàng là rõ ràng hoặc không quan trọng.

Tuy nhiên, không hoàn hảo, tôi đang cố làm theo lời khuyên của chú Bob - và nó đang cải thiện mã của tôi.

Trong những trường hợp hiếm hoi mà một phương thức dường như đòi hỏi nhiều thông tin hơn, giới thiệu một đối tượng tham số là một ý tưởng tốt. Thông thường, tôi thấy đây là bước đầu tiên để phát hiện ra một khái niệm (đối tượng) mới là chìa khóa cho thuật toán của tôi.


Tôi chắc chắn đồng ý với bạn! Tuyên bố đầu tiên của tôi là nhằm mục đích nhận ra rằng đây không phải là một điều điển hình đối với tôi, haha. Nhưng trong trường hợp tôi thấy tôi thực sự cần phải truyền một số tham số và nó không đáng để cấu trúc lại toàn bộ chương trình, tôi tự hỏi về việc đặt hàng.
Casey Patton

3
ho PHP ho . Tôi xin lỗi - bạn đã nói điều gì đó về việc không lo lắng về thứ tự của các tham số?
Craige

Bạn sẽ không có một hàm tạo cho đối tượng tham số của mình mà chỉ cần nhiều đối số?
gièm pha

Không - bởi vì đối tượng tham số có thể được "xây dựng" qua một số câu lệnh theo cách dễ đọc hơn.
Bevan

2
@Bevan: điều này rất gây tranh cãi. Xây dựng các đối tượng theo cách này có nghĩa là chúng không thể bất biến nữa; giữ cho đối tượng của bạn bất biến bất cứ khi nào có thể tuy nhiên là một cách tuyệt vời khác để tăng khả năng bảo trì.
tdammers

10

Tôi cố gắng đặt các tham số IN trước, tham số OUT thứ hai. Ngoài ra còn có một số thứ tự tự nhiên, ví dụ như createPoint(double x, double y)rất thích hợp createPoint(double y, double x).


5
Đôi khi, điều ngược lại là tốt hơn, ví dụ, khi luôn luôn chỉ có một đối số OUT và một số lượng khác nhau trong các đối số, như trong addAllTo(target, something1, something2).
maaartinus

Mặc dù tôi tuân theo quy tắc tương tự, tôi cố gắng tránh các tham số OUT bất cứ khi nào có thể và hầu hết các lập trình viên giỏi cũng vậy. Vì vậy, số lượng chức năng mà khuyến nghị này thực sự giúp OP nên khá ít.
Doc Brown

7
@DocBrown Bạn thực sự không nên cố gắng tránh các lập trình viên giỏi, họ có thể hữu ích để có xung quanh.
RyanfaeScotland 17/2/2015

@RyanfaeScotland: chết tiệt, tôi nên đọc bình luận của mình hai lần trước khi đăng chúng (hoặc ít nhất trong vòng năm phút tôi có thể thay đổi chúng) ;-)
Doc Brown

6

Tôi chưa bao giờ thấy một "thực tiễn tốt nhất" được ghi lại về chủ đề cụ thể này, nhưng tiêu chuẩn cá nhân của tôi là liệt kê chúng theo thứ tự chúng sẽ xuất hiện trong phương thức mà chúng đang được sử dụng hoặc nếu phương pháp này là một truyền qua một lớp dữ liệu tôi sẽ liệt kê chúng theo thứ tự chúng sẽ xuất hiện trong lược đồ db hoặc các phương thức của lớp dữ liệu.

Ngoài ra, khi có nhiều quá tải của một phương thức, tôi nhận thấy rằng cách điển hình là liệt kê chúng bắt đầu bằng các tham số chung cho tất cả (hoặc hầu hết) các phương thức với mỗi phương thức khác nhau được thêm vào cuối cho mỗi phương thức quá tải như :

void func1(string param) { }
void func2(string param, int param2) { }
void func3(string param, string param3) { }
void func3(string param, int param2, string param3) { }


3

Tôi thường tuân theo quy ước C / C ++ về việc đặt các consttham số trước (nghĩa là các tham số bạn truyền vào theo giá trị), và sau đó là các tham số mà bạn truyền vào bằng tham chiếu. Đây có thể không nhất thiết là phương thức gọi hàm chính xác, nhưng, nếu bạn quan tâm đến cách mỗi trình biên dịch xử lý các tham số, hãy xem các liên kết sau để biết các quy tắc chi phối và / hoặc thứ tự các tham số được đẩy lên ngăn xếp.

http://msdn.microsoft.com/en-us/l Library / zthk2dkh% 28v = vs.80% 29.aspx

http://en.wikipedia.org/wiki/Calling_convent


Một liên kết khác mà bạn có thể quan tâm là msdn.microsoft.com/en-us/l Library / 984x0h58% 28v = vs.71% 29.aspx Để biết các hàm đệ quy, hãy xem liên kết sau. ấn phẩm.gbdirect.co.uk / c_book / ch CHƯƠNG4 / Không phải là tôi đã quên nhưng, là một người dùng mới, tôi không thể đăng một bình luận có nhiều hơn hai liên kết .... thật là bực bội!
Hóa đơn

1

Tôi thường chỉ đi với thứ tự tham số "những gì trông ít cyprtic". Càng ít lần tôi cần đi đến định nghĩa phương thức / hàm thì càng tốt. Và thật tuyệt khi có các tham số được đặt tên mô tả như những gì chúng được sử dụng cho, theo cách đó khi chú giải công cụ nhỏ bật lên (VS) thì điều đó càng dễ dàng hơn.

Nếu bạn có các dòng và dòng tham số, bạn có thể muốn xem xét một thiết kế khác. Bước lại và xem làm thế nào bạn có thể chia nó thành nhiều hàm / phương thức hơn. Chỉ là một ý tưởng, nhưng khi tôi có hàng tá tham số trong hàm thì hầu như không phải là vấn đề tham số, mà là vấn đề thiết kế.


2
"cyprtic": một cách tuyệt vời để đưa ra quan điểm.
Bevan

2
Bạn chưa bao giờ mắc lỗi đánh máy trước đây, @Bevan?

1
Tôi có lỗi chính tả mọi lúc - viết cyprtic rất tốt, tôi nghĩ rằng đó là mục đích . Xin vui lòng thay đổi nó trở lại, nó giúp đưa ra quan điểm của bạn, ngay cả khi đó là một tai nạn.
Bevan

1
@Bevan, haha ​​được rồi tôi hiểu bạn đang nói gì. Điểm tốt! Nó đã thay đổi trở lại =)

1

Đôi khi (hiếm khi), có vẻ như việc tạo ra một hàm cần một lượng tham số kha khá là con đường tốt nhất.

Sử dụng một vài tham số thường là một chỉ báo rõ ràng, rằng bạn vi phạm SRP trong phương pháp này. Một phương thức, cần nhiều tham số không chắc chỉ làm một việc. Excpetion có thể là một hàm toán học hoặc một phương thức cấu hình, trong đó thực sự cần một vài tham số như vậy. Tôi sẽ tránh nhiều thông số vì ma quỷ tránh nước thánh. Càng sử dụng nhiều tham số trong một phương thức, cơ hội càng cao, phương thức đó (quá) phức tạp; sự phức tạp hơn có nghĩa là: khó duy trì hơn và đó là ít mong muốn hơn.

Tuy nhiên, khi tôi làm, tôi cảm thấy như tôi thường chọn thứ tự các tham số một cách ngẫu nhiên. Tôi thường đi theo "thứ tự quan trọng", với tham số quan trọng nhất trước tiên.

Trong prinipl bạn đang chọn ngẫu nhiên . Tất nhiên bạn có thể nghĩ tham số A có liên quan nhiều hơn tham số B ; nhưng đó có thể không phải là trường hợp đối với người dùng API của bạn, người cho rằng B là tham số phù hợp nhất. Vì vậy, ngay cả khi bạn đã chú ý trong việc lựa chọn thứ tự - đối với những người khác, điều đó có vẻ ngẫu nhiên .

Có cách nào tốt hơn để làm điều này? Có cách "thực hành tốt nhất" để đặt hàng các tham số giúp tăng cường sự rõ ràng không?

Có một số cách:

a) Trường hợp tầm thường: Không sử dụng nhiều hơn một tham số.

b) Vì bạn không chỉ định, ngôn ngữ bạn đã chọn, có khả năng là bạn đã chọn ngôn ngữ có tham số được đặt tên . Đây là đường cú pháp đẹp cho phép bạn nới lỏng tầm quan trọng của việc sắp xếp các thông số:fn(name:"John Doe", age:36)

Không phải ngôn ngữ nào cũng cho phép những thứ tốt đẹp như vậy. Sau đó thì sao?

c) Bạn có thể sử dụng một từ điển / Hashmap / Mảng liên kết làm tham số: ví dụ: Javascript sẽ cho phép các điều sau: fn({"name":"John Doe", age:36})không xa (b).

d) Tất nhiên nếu bạn làm việc với một ngôn ngữ được gõ tĩnh như Java. bạn có thể sử dụng Hashmap , nhưng bạn sẽ mất thông tin loại (ví dụ: khi làm việc với HashMap<String, Object>) khi các tham số có các loại khác nhau (và cần truyền).

Bước hợp lý tiếp theo sẽ là vượt qua Object(nếu bạn đang sử dụng Java) với các thuộc tính phù hợp hoặc thứ gì đó nhẹ hơn như một cấu trúc (nếu bạn viết ví dụ C # hoặc C / C ++).

Quy tắc của ngón tay cái:

1) Trường hợp tốt nhất - phương pháp của bạn không cần tham số nào cả

2) Trường hợp tốt - phương pháp của bạn cần một tham số

3) Trường hợp chấp nhận được - phương thức của bạn cần hai tham số

4) Tất cả các trường hợp khác nên được tái cấu trúc


0

Thông thường, một đối tượng phức tạp như một tham số sẽ tốt hơn - phiên bản của các thông số được đặt tên của một người nghèo hoạt động trên hầu hết các nền tảng. Và mở ra cánh cửa cho các tham số với hành vi để khởi động.

Để biết ví dụ về hầu hết những điều bạn không nên làm, bạn có thể muốn thử đọc tài liệu thư viện chuẩn của PHP.


0

Tôi thường đặt hàng chúng với yêu cầu trước, hơn là bằng một số biện pháp kết hợp quan trọng và tần suất sử dụng theo một "cảm giác" (có thể được xem là ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency)) và không theo bất kỳ thực tiễn cụ thể nào.

Tuy nhiên, như những người khác đã lưu ý, tôi nghĩ vấn đề tiềm ẩn khiến vấn đề này là sử dụng quá nhiều tham số (IMHO, bất cứ điều gì> 3 là quá nhiều) và đó là vấn đề thực sự mà bạn nên giải quyết. Có một bài viết thú vị về điều đó tại blog của rebecca murphey.

Tôi nghĩ rằng khi bạn chỉ có 1-3 đối số, thứ tự đúng là khá rõ ràng và bạn chỉ "cảm thấy" điều gì đúng.


0

Tương tự như câu trả lời của @Wyatt Barnetts, bất cứ điều gì nhiều hơn một vài tham số hoặc tham số rất rõ ràng cho phương thức, tôi khuyên bạn nên chuyển một đối tượng thay thế. Điều này thường dễ dàng hơn để cập nhật / bảo trì, dễ đọc hơn và loại bỏ sự cần thiết phải lo lắng về việc đặt hàng . Ngoài ra, quá nhiều tham số cho một phương thức là mùi mã và có các mẫu tái cấu trúc phổ biến mà bạn có thể làm theo để giúp sửa nó.

Ví dụ rõ ràng:

public int add(int left, int right)
{
  return left + right;
}

Vì đây là một ví dụ được xác định khá rõ ràng và bổ sung là giao hoán (thứ tự không thành vấn đề) nên chỉ cần đi với nó.

Tuy nhiên, nếu bạn thêm một cái gì đó phức tạp hơn:

public SomeComplexReturnValue Calculate(int i, float f, string s, object o)
{
  // do work here
}

Sẽ trở thành:

public class SomeComplexInputForCalculation
{
  public int i; 
  public float f;
  public string s; 
  public object o;
}

public SomeComplexReturnValue Calculate(SomeComplexInputForCalculation input)
{
  // do work here
}

Hi vọng điêu nay co ich...


0

Đặt nó theo bất cứ cách nào bạn nghĩ rằng cà ri sẽ có lợi nhất. Ví dụ, tham số chức năng đầu tiên.


0

"Quan trọng đầu tiên" không có nghĩa là rất nhiều. Có một số quy ước.

Nếu bạn vượt qua đối tượng gọi (thường được đặt tên người gửi), điều đó sẽ đi trước.

Cần có một số lưu loát trong danh sách, có nghĩa là bạn nên biết tranh luận là gì khi bạn đọc nó. Thí dụ:

CopyFolder (đường dẫn chuỗi, đệ quy bool);

Nếu bạn đặt đệ quy lên trước, nó sẽ gây nhầm lẫn vì chưa có ngữ cảnh. Nếu bây giờ bạn đã nói về việc sao chép (1), một thư mục (2), thì đối số đệ quy bắt đầu có ý nghĩa.

Điều này cũng làm cho các tính năng giống như IntelliSense hoạt động tốt: người dùng học khi anh ta điền vào các đối số, anh ta xây dựng sự hiểu biết về phương pháp và những gì nó làm. Tương tự như vậy, quá tải nên duy trì cùng một thứ tự cho các phần bằng nhau.

Sau đó, bạn vẫn có thể thấy có các đối số "bằng nhau" trong khía cạnh này và bạn có thể bị cám dỗ để thứ tự phụ thuộc vào loại đối số. Chỉ vì có một vài chuỗi liên tiếp và sau đó một vài booleans trông đẹp hơn. Ở một mức độ nào đó, điều này sẽ trở thành một nghệ thuật chứ không phải là một kỹ năng.

Tôi không quan tâm lắm đến tuyên bố rằng bạn nên bọc tất cả các đối số vào một đối tượng chỉ để kết thúc bằng một đối số duy nhất. Đó chỉ là tự đánh lừa chính mình (nó không làm cho phương thức trở nên ít phức tạp hơn, nó vẫn có tất cả các đối số này, bạn chỉ cần che giấu chúng). Điều này có thể vẫn thuận tiện để thực hiện nếu bạn chuyển tập hợp từ phương thức này sang phương pháp khác một vài lần, việc tái cấu trúc chắc chắn sẽ trở nên dễ dàng hơn rất nhiều, nhưng thiết kế khôn ngoan chỉ là giả vờ bạn đang tạo ra sự khác biệt. Nó không giống như bạn sẽ kết thúc với một đối tượng có ý nghĩa đại diện cho một cái gì đó, nó sẽ chỉ là một loạt các đối số, không khác với danh sách trong khai báo phương thức. Nó sẽ không làm cho chú Bob hạnh phúc.

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.