Các tham số tùy chọn hoặc các hàm tạo quá tải


28

Tôi đang triển khai DelegateCommandvà khi tôi sắp triển khai (các) nhà xây dựng, tôi đã đưa ra hai lựa chọn thiết kế sau:

1: Có nhiều nhà xây dựng quá tải

public DelegateCommand(Action<T> execute) : this(execute, null) { }

public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
{
    this.execute = execute;
    this.canExecute = canExecute;
}

2: Chỉ có một hàm tạo với tham số tùy chọn

public DelegateCommand(Action<T> execute, Func<T, bool> canExecute = null)
{
    this.execute = execute;
    this.canExecute = canExecute;
}

Tôi không biết nên sử dụng cái nào vì tôi không biết những lợi thế / bất lợi có thể xảy ra với một trong hai cách được đề xuất. Cả hai có thể được gọi như thế này:

var command = new DelegateCommand(this.myExecute);
var command2 = new DelegateCommand(this.myExecute, this.myCanExecute);

Ai đó có thể vui lòng chỉ cho tôi đi đúng hướng và đưa ra phản hồi?


4
HÔN và YAGNI. Trong trường hợp nghi ngờ, thực hiện cả hai. Sau một thời gian, thực hiện tìm kiếm các tham chiếu đến cả hai hàm tạo. Tôi sẽ không ngạc nhiên nếu một trong số chúng không bao giờ được tiêu thụ ra bên ngoài. Hoặc tiêu thụ nhẹ. Đây là một cái gì đó dễ dàng để thực hiện phân tích tĩnh của mã.
Laiv

1
Các nhà xây dựng tĩnh (như Bitmap.FromFile) cũng là một lựa chọn
BlueRaja - Danny Pflughoeft 27/03/18


2
@Laiv tôi có thiếu thứ gì không? Chúng được sử dụng theo cùng một cách và do đó có cùng chữ ký. Bạn không thể tìm kiếm tài liệu tham khảo và cho biết người gọi đang nghĩ gì. Nghe có vẻ giống như bạn đang đề cập đến việc OP có nên tranh luận lần thứ hai hay không, nhưng đó không phải là điều OP đang hỏi (và họ có thể biết chắc chắn rằng đôi khi họ cần cả hai, do đó họ hỏi).
Kat

2
@Voo Trình biên dịch cho Openedge | Progress 10.2B bỏ qua chúng. Khá nhiều người đã giết chết chiến lược thay đổi phương pháp không phá vỡ của chúng tôi; thay vào đó, chúng tôi cần sử dụng quá tải cho cùng một hiệu ứng.
Bret

Câu trả lời:


24

Tôi thích nhiều hàm tạo hơn các giá trị mặc định và cá nhân tôi không thích ví dụ hai hàm tạo của bạn, nó nên được triển khai khác nhau.

Lý do sử dụng nhiều hàm tạo là vì hàm chính có thể kiểm tra xem tất cả các tham số có phải là null không và chúng có hợp lệ hay không trong khi các hàm tạo khác có thể cung cấp các giá trị mặc định cho hàm chính.

Tuy nhiên, trong các ví dụ của bạn, không có sự khác biệt giữa chúng bởi vì ngay cả hàm tạo thứ cấp cũng vượt qua nullnhư một giá trị mặc định và hàm tạo chính cũng phải biết giá trị mặc định. Tôi nghĩ rằng nó không nên.

Điều này có nghĩa là nó sẽ sạch hơn và tách biệt tốt hơn nếu được thực hiện theo cách này:

public DelegateCommand(Action<T> execute) : this(execute, _ => true) { }

public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
{
    this.execute = execute ?? throw new ArgumentNullException(..);
    this.canExecute = canExecute ?? throw new ArgumentNullException(..);
}

lưu ý _ => truechuyển đến hàm tạo chính hiện đang kiểm tra tất cả các tham số nullvà không quan tâm đến bất kỳ giá trị mặc định nào.


Tuy nhiên, điểm quan trọng nhất là khả năng mở rộng. Nhiều nhà xây dựng sẽ an toàn hơn khi có khả năng bạn sẽ mở rộng mã của mình trong tương lai. Nếu bạn thêm nhiều tham số bắt buộc và cuối cùng các tham số tùy chọn phải đến, bạn sẽ phá vỡ tất cả các triển khai hiện tại của mình. Bạn có thể tạo hàm tạo cũ [Obsolete]và thông báo cho người dùng rằng nó sẽ bị xóa cho họ thời gian để chuyển sang triển khai mới mà không phá vỡ mã của họ ngay lập tức.


Mặt khác, việc tạo quá nhiều tham số tùy chọn cũng sẽ gây nhầm lẫn bởi vì nếu một số trong số chúng được yêu cầu trong một kịch bản và tùy chọn trong một kịch bản khác, bạn sẽ cần nghiên cứu tài liệu thay vì chỉ chọn đúng hàm tạo bằng cách chỉ cần nhìn vào tham số của nó.


12
Mặt khác, việc tạo quá nhiều tham số tùy chọn sẽ gây nhầm lẫn ... Thành thật mà nói, có quá nhiều tham số (bất kể chúng có tùy chọn hay không) là khó hiểu.
Andy

1
@DavidPacker Tôi đồng ý với bạn, nhưng tôi nghĩ có bao nhiêu tham số là quá nhiều là một câu chuyện khác ;-)
t3chb0t 27/03/18

2
Có một sự khác biệt khác giữa việc có một hàm tạo bỏ qua tham số so với hàm tạo có mặc định cho tham số. Trong trường hợp đầu tiên, người gọi có thể tránh việc truyền tham số một cách rõ ràng, trong khi đó trong trường hợp sau, người gọi không thể - vì không có tham số nào giống như truyền giá trị mặc định. Nếu nhà xây dựng cần tạo sự khác biệt này, thì hai nhà xây dựng là cách duy nhất để đi.
Gary McGill

1
Ví dụ, giả sử tôi có một lớp định dạng các chuỗi, mà tôi có thể tùy ý xây dựng với một CultureInfođối tượng. Tôi muốn một API cho phép CultureInfotham số được cung cấp thông qua một tham số bổ sung, nhưng nhấn mạnh rằng nếu nó được cung cấp thì không nên null. Theo cách đó, nullcác giá trị tình cờ không bị hiểu sai là "không".
Gary McGill

Tôi không chắc khả năng mở rộng thực sự là một lý do chống lại các tham số tùy chọn; nếu bạn có tất cả các tham số cần thiết và thay đổi số lượng chúng, bạn sẽ phải tạo một hàm tạo mới và Obsoletehàm cũ nếu bạn muốn tránh phá vỡ mọi thứ, cho dù bạn cũng có các tham số tùy chọn hay không. Với các tham số tùy chọn, bạn chỉ phải thực hiện Obsoletenếu bạn loại bỏ một.
Herohtar

17

Xem xét điều duy nhất bạn đang làm trong hàm tạo là phép gán đơn giản, giải pháp hàm tạo duy nhất có thể là lựa chọn tốt hơn trong trường hợp của bạn. Hàm tạo khác không cung cấp chức năng bổ sung và rõ ràng từ thiết kế của hàm tạo với hai tham số mà đối số thứ hai không cần phải cung cấp.

Nhiều hàm tạo có ý nghĩa khi bạn xây dựng một đối tượng từ các loại khác nhau. Trong trường hợp đó, các hàm tạo là sự thay thế của một nhà máy bên ngoài vì chúng xử lý các tham số đầu vào và định dạng chúng thành một biểu diễn thuộc tính bên trong chính xác của lớp đang được xây dựng. Tuy nhiên, điều đó không xảy ra trong trường hợp của bạn do đó tại sao một nhà xây dựng nên là quá đủ.


3

Tôi nghĩ có hai trường hợp khác nhau mà mỗi cách tiếp cận có thể tỏa sáng.

Đầu tiên, khi chúng ta có các hàm tạo đơn giản (thường là trường hợp, theo kinh nghiệm của tôi), tôi sẽ xem xét các đối số tùy chọn để tỏa sáng.

  1. Họ giảm thiểu mã phải được viết (và do đó cũng phải đọc).
  2. Bạn có thể đảm bảo rằng tài liệu ở một nơi và không bị lặp lại (điều này rất tệ vì nó mở ra một khu vực phụ có thể bị lỗi thời).
  3. Nếu bạn có nhiều đối số tùy chọn, bạn có thể tránh việc có một tập hợp các hàm tạo rất khó hiểu. Heck, thậm chí chỉ với 2 đối số tùy chọn (không liên quan với nhau), nếu bạn muốn các hàm tạo riêng biệt, quá tải, bạn phải có 4 hàm tạo (phiên bản không có bất kỳ, phiên bản nào với mỗi phiên bản và cả hai phiên bản). Điều này rõ ràng là không có quy mô tốt.

Buuuut, có những trường hợp trong đó các đối số tùy chọn trong các hàm tạo chỉ làm cho mọi thứ rõ ràng khó hiểu hơn. Ví dụ rõ ràng là khi các đối số tùy chọn này là độc quyền (nghĩa là không thể được sử dụng cùng nhau). Việc các nhà xây dựng quá tải chỉ cho phép kết hợp các đối số thực sự hợp lệ sẽ đảm bảo biên dịch thời gian thực thi ràng buộc này. Điều đó nói rằng, bạn cũng nên tránh thậm chí gặp phải trường hợp này (ví dụ: với nhiều lớp kế thừa từ một cơ sở, trong đó mỗi lớp thực hiện hành vi độc quyền).


+1 để đề cập đến vụ nổ hoán vị với nhiều tham số tùy chọn.
Jpsy
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.