Tham số để kiểm soát xem có nên ném ngoại lệ hoặc trả về null - thực hành tốt không?


24

Tôi thường bắt gặp các phương thức / hàm có tham số boolean bổ sung để kiểm soát xem một ngoại lệ có bị lỗi hay không được trả về null.

Đã có những cuộc thảo luận về vấn đề nào trong số đó là sự lựa chọn tốt hơn trong trường hợp nào, vì vậy chúng ta đừng tập trung vào vấn đề này ở đây. Xem ví dụ Trả lại giá trị ma thuật, ném ngoại lệ hoặc trả lại sai khi thất bại?

Thay vào đó chúng ta hãy cho rằng có một lý do chính đáng tại sao chúng ta muốn hỗ trợ cả hai cách.

Cá nhân tôi nghĩ rằng một phương pháp như vậy nên được chia thành hai: Một phương pháp ném ngoại lệ cho thất bại, phương pháp khác trả về null khi thất bại.

Vậy, cái nào tốt hơn?

A: Một phương thức với $exception_on_failuretham số.

/**
 * @param int $id
 * @param bool $exception_on_failure
 *
 * @return Item|null
 *   The item, or null if not found and $exception_on_failure is false.
 * @throws NoSuchItemException
 *   Thrown if item not found, and $exception_on_failure is true.
 */
function loadItem(int $id, bool $exception_on_failure): ?Item;

B: Hai phương pháp riêng biệt.

/**
 * @param int $id
 *
 * @return Item|null
 *   The item, or null if not found.
 */
function loadItemOrNull(int $id): ?Item;

/**
 * @param int $id
 *
 * @return Item
 *   The item, if found (exception otherwise).
 *
 * @throws NoSuchItemException
 *   Thrown if item not found.
 */
function loadItem(int $id): Item;

EDIT: C: Cái gì khác?

Rất nhiều người đã đề xuất các lựa chọn khác, hoặc cho rằng cả A và B đều thiếu sót. Những đề xuất hoặc ý kiến ​​như vậy đều được chào đón, có liên quan và hữu ích. Một câu trả lời hoàn chỉnh có thể chứa thông tin bổ sung như vậy, nhưng cũng sẽ giải quyết câu hỏi chính về việc liệu một tham số để thay đổi chữ ký / hành vi có phải là một ý tưởng tốt hay không.

Ghi chú

Trong trường hợp ai đó đang tự hỏi: Các ví dụ là trong PHP. Nhưng tôi nghĩ rằng câu hỏi được áp dụng trên các ngôn ngữ miễn là chúng có phần giống với PHP hoặc Java.


5
Mặc dù tôi phải làm việc với PHP và khá thành thạo, nhưng nó đơn giản là một ngôn ngữ tồi và thư viện tiêu chuẩn của nó ở khắp mọi nơi. Đọc eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design để tham khảo. Vì vậy, không có gì đáng ngạc nhiên khi một số nhà phát triển PHP áp dụng các thói quen xấu. Nhưng tôi chưa thấy mùi thiết kế đặc biệt này.
Polygnome

Tôi đang thiếu một điểm quan trọng trong các câu trả lời được đưa ra: khi nào bạn sẽ sử dụng cái này hay cái kia. Bạn sẽ sử dụng phương pháp ngoại lệ trong trường hợp một mục không được tìm thấy sẽ bất ngờ và được coi là một lỗi (thời gian để hoảng loạn). Bạn sẽ sử dụng phương pháp Thử ... trong trường hợp một mục bị thiếu không có khả năng xảy ra và chắc chắn không phải là lỗi mà chỉ là khả năng bạn đưa vào kiểm soát luồng thông thường.
Martin Maat


1
@Polygnome Bạn nói đúng, các chức năng thư viện tiêu chuẩn ở khắp mọi nơi và có rất nhiều mã kém tồn tại và có vấn đề một quy trình cho mỗi yêu cầu. Nhưng nó đang trở nên tốt hơn với mỗi phiên bản. Các kiểu và mô hình đối tượng thực hiện tất cả hoặc hầu hết những điều mà người ta có thể mong đợi từ nó. Tôi muốn xem các kiểu tổng quát, đồng và chống chỉ định, các kiểu gọi lại chỉ định một chữ ký, v.v ... Rất nhiều điều này đang được thảo luận hoặc trên đường thực hiện. Tôi nghĩ rằng định hướng chung là tốt, mặc dù các quirks thư viện tiêu chuẩn sẽ không biến mất dễ dàng.
donquixote

4
Một đề nghị: thay vì loadItemOrNull(id), hãy xem xét liệu loadItemOr(id, defaultItem)có ý nghĩa với bạn. Nếu mục là một Chuỗi hoặc số nó thường làm.
user949300

Câu trả lời:


35

Bạn đã đúng: hai phương pháp tốt hơn nhiều vì điều đó, vì nhiều lý do:

  1. Trong Java, chữ ký của phương thức có khả năng ném ngoại lệ sẽ bao gồm ngoại lệ này; phương pháp khác sẽ không. Nó làm cho nó đặc biệt rõ ràng những gì mong đợi từ người này và người kia.

  2. Trong các ngôn ngữ như C # trong đó chữ ký của phương thức không cho biết gì về các ngoại lệ, các phương thức công khai vẫn phải được ghi lại và tài liệu đó bao gồm các ngoại lệ. Tài liệu về một phương pháp duy nhất sẽ không dễ dàng.

    Ví dụ của bạn là hoàn hảo: các nhận xét trong đoạn mã thứ hai trông rõ ràng hơn nhiều và tôi thậm chí sẽ rút ngắn Mục này, nếu được tìm thấy (ngoại trừ trường hợp khác). mô tả bạn đã cho nó là tự giải thích.

  3. Trong trường hợp của một phương thức, có một vài trường hợp bạn muốn chuyển đổi giá trị của tham số boolean trong thời gian chạy và nếu bạn làm như vậy, điều đó có nghĩa là người gọi sẽ phải xử lý cả hai trường hợp (một nullphản hồi ngoại lệ ), làm cho mã khó khăn hơn nhiều so với nó cần phải có. Vì sự lựa chọn được thực hiện không phải trong thời gian chạy, nhưng khi viết mã, hai phương thức có ý nghĩa hoàn hảo.

  4. Một số khung, chẳng hạn như .NET Framework, đã thiết lập các quy ước cho tình huống này và họ giải quyết nó bằng hai phương pháp, giống như bạn đề xuất. Sự khác biệt duy nhất là họ sử dụng một mô hình được giải thích bởi Ewan trong câu trả lời của anh ấy , vì vậy, int.Parse(string): intném một ngoại lệ, trong khi int.TryParse(string, out int): boolkhông. Quy ước đặt tên này rất mạnh trong cộng đồng .NET và nên được tuân theo bất cứ khi nào mã phù hợp với tình huống bạn mô tả.


1
Cảm ơn bạn, đây là câu trả lời tôi đang tìm kiếm! Mục đích là tôi đã bắt đầu một cuộc thảo luận về vấn đề này cho Drupal CMS, drupal.org/project/drupal/issues/2932772 và tôi không muốn điều này là về sở thích cá nhân của mình, nhưng sao lưu nó với phản hồi từ người khác.
donquixote

4
Trên thực tế, truyền thống lâu đời đối với ít nhất .NET là KHÔNG sử dụng hai phương thức, mà thay vào đó chọn lựa chọn đúng cho nhiệm vụ phù hợp. Các ngoại lệ dành cho các trường hợp đặc biệt, không xử lý luồng điều khiển dự kiến. Không phân tích một chuỗi thành một số nguyên? Không phải là một trường hợp rất bất ngờ hoặc đặc biệt. int.Parse()được coi là một quyết định thiết kế thực sự tồi tệ, đó chính xác là lý do tại sao nhóm .NET đã đi trước và thực hiện TryParse.
Voo

1
Cung cấp hai phương pháp thay vì suy nghĩ về loại trường hợp sử dụng mà chúng ta đang xử lý, là cách dễ dàng: Đừng nghĩ về những gì bạn đang làm, thay vào đó, hãy đặt trách nhiệm lên tất cả người dùng API của bạn. Chắc chắn nó hoạt động, nhưng đó không phải là đặc điểm nổi bật của thiết kế API tốt (hoặc bất kỳ thiết kế nào cho vấn đề này. Đọc, ví dụ như Joel đảm nhận việc này .
Voo

@Voo Điểm hợp lệ. Thực sự cung cấp hai phương pháp đặt sự lựa chọn vào người gọi. Có lẽ đối với một số giá trị tham số, một mục dự kiến ​​sẽ tồn tại, trong khi đối với các giá trị tham số khác, mục không tồn tại được coi là trường hợp thông thường. Có lẽ thành phần này được sử dụng trong một ứng dụng trong đó các mục luôn được dự kiến ​​tồn tại và trong một ứng dụng khác nơi các mục không tồn tại được coi là bình thường. Có lẽ người gọi gọi ->itemExists($id)trước khi gọi ->loadItem($id). Hoặc có lẽ nó chỉ là một lựa chọn được thực hiện bởi những người khác trong quá khứ, và chúng ta phải coi đó là điều hiển nhiên.
donquixote

1
Lý do 1b: Một số ngôn ngữ (Haskell, Swift) yêu cầu không có giá trị để có mặt trong chữ ký. Cụ thể, Haskell có một loại hoàn toàn khác cho các giá trị nullable ( data Maybe a = Just a | Nothing).
John Dvorak

9

Một biến thể thú vị là ngôn ngữ Swift. Trong Swift, bạn khai báo một hàm là "ném", nghĩa là nó được phép ném lỗi (tương tự nhưng không hoàn toàn giống như nói ngoại lệ Java). Người gọi có thể gọi chức năng này theo bốn cách:

a. Trong một tuyên bố thử / bắt bắt và xử lý ngoại lệ.

b. Nếu người gọi tự tuyên bố là ném, chỉ cần gọi nó và bất kỳ lỗi nào được ném sẽ biến thành lỗi do người gọi ném.

c. Đánh dấu cuộc gọi chức năng có try!nghĩa là "Tôi chắc chắn rằng cuộc gọi này sẽ không thực hiện". Nếu chức năng được gọi không ném, ứng dụng được đảm bảo bị sập.

d. Đánh dấu cuộc gọi hàm có try?nghĩa là "Tôi biết hàm có thể ném nhưng tôi không quan tâm chính xác lỗi nào được ném". Điều này thay đổi giá trị trả về của hàm từ loại " T" sang loại " optional<T>" và một ngoại lệ được ném sẽ trở thành số không.

(a) và (d) là những trường hợp bạn đang hỏi về. Điều gì xảy ra nếu hàm có thể trả về con số không có thể ném ngoại lệ? Trong trường hợp đó, loại giá trị trả về sẽ là " optional<R>" đối với một số loại R và (d) sẽ thay đổi giá trị này thành " optional<optional<R>>" hơi khó hiểu và khó hiểu nhưng hoàn toàn ổn. Và một hàm Swift có thể trả về optional<Void>, vì vậy (d) có thể được sử dụng để ném các hàm trả về Void.


2

Tôi thích bool TryMethodName(out returnValue)cách tiếp cận.

Nó cung cấp cho bạn một dấu hiệu kết luận về việc phương thức có thành công hay không và việc đặt tên khớp với phương thức ném ngoại lệ trong khối thử bắt.

Nếu bạn trả về null, bạn không biết nếu nó thất bại hoặc giá trị trả về là null hợp pháp.

ví dụ:

//throws exceptions when error occurs
Item LoadItem(int id);

//returns false when error occurs
bool TryLoadItem(int id, out Item item)

sử dụng ví dụ (ra có nghĩa là vượt qua bằng cách tham chiếu chưa được khởi tạo)

Item i;
if(TryLoadItem(3, i))
{
    Print(i.Name);
}
else
{
    Print("unable to load item :(");
}

Xin lỗi, bạn đã mất tôi ở đây. " bool TryMethodName(out returnValue)Cách tiếp cận " của bạn sẽ trông như thế nào trong ví dụ ban đầu?
donquixote

được chỉnh sửa để thêm một ví dụ
Ewan

1
Vì vậy, bạn sử dụng một tham số phụ tham chiếu thay vì giá trị trả về, vì vậy bạn có giá trị trả về miễn phí cho thành công bool? Có ngôn ngữ lập trình nào hỗ trợ từ khóa "out" này không?
donquixote

2
vâng, xin lỗi đã không nhận ra 'out' là dành riêng cho c #
Ewan

1
không phải lúc nào cũng không Nhưng nếu mục 3 null thì sao? bạn sẽ không biết có lỗi hay không
Ewan

2

Thông thường, một tham số boolean chỉ ra một hàm có thể được chia thành hai và theo quy tắc, bạn phải luôn chia nó ra thay vì truyền vào boolean.


1
Tôi sẽ không ngoại trừ điều này như một quy tắc mà không cần thêm một số phẩm chất hoặc sắc thái. Xóa một boolean làm đối số có thể buộc bạn phải viết một chữ câm if / other ở một nơi khác và do đó bạn mã hóa dữ liệu trong mã viết của mình chứ không phải trong các biến.
Gerard

@Gerard bạn có thể cho tôi một ví dụ được không?
Tối đa

@Max Khi bạn có một biến boolean b: Thay vì gọi foo(…, b);bạn phải viết if (b) then foo_x(…) else foo_y(…);và lặp lại các đối số khác, hoặc đại loại như ((b) ? foo_x : foo_y)(…)nếu ngôn ngữ có toán tử ternary và các hàm / phương thức lớp đầu tiên. Và điều này thậm chí có thể lặp lại từ một số nơi khác nhau trong chương trình.
BlackJack

@BlackJack tốt yeah tôi có thể đồng ý với bạn. Tôi nghĩ về ví dụ này, if (myGrandmaMadeCookies) eatThem() else makeFood()vâng tôi có thể gói một chức năng khác như thế này checkIfShouldCook(myGrandmaMadeCookies). Tôi tự hỏi liệu sắc thái mà bạn đề cập có liên quan đến việc chúng ta chuyển qua một boolean về cách chúng ta muốn hàm hoạt động hay không, như trong câu hỏi ban đầu, so với việc chúng ta chuyển một số thông tin về mô hình của chúng ta, như trong ví dụ bà tôi vừa đưa ra.
Tối đa

1
Các sắc thái được đề cập trong bình luận của tôi đề cập đến "bạn nên luôn luôn". Có thể viết lại nó thành "nếu a, b và c được áp dụng thì [...]". "Quy tắc" mà bạn đề cập là một mô hình tuyệt vời, nhưng rất khác nhau về trường hợp sử dụng.
Gerard

1

Clean Code khuyên bạn nên tránh các đối số cờ boolean, vì ý nghĩa của chúng không rõ ràng tại trang web cuộc gọi:

loadItem(id, true) // does this throw or not? We need to check the docs ...

trong khi các phương thức riêng biệt có thể sử dụng tên biểu cảm:

loadItemOrNull(id); // meaning is obvious; no need to refer to docs

1

Nếu tôi phải sử dụng A hoặc B thì tôi sẽ sử dụng B, hai phương pháp riêng biệt, vì những lý do được nêu trong câu trả lời của Arseni Mourzenkos .

Nhưng có một phương thức khác 1 : Trong Java, nó được gọi Optional, nhưng bạn có thể áp dụng khái niệm tương tự cho các ngôn ngữ khác nơi bạn có thể định nghĩa các loại của riêng mình, nếu ngôn ngữ chưa cung cấp một lớp tương tự.

Bạn xác định phương pháp của bạn như thế này:

Optional<Item> loadItem(int id);

Trong phương pháp của bạn, bạn sẽ trả lại Optional.of(item)nếu bạn tìm thấy mục hoặc bạn trả lại Optional.empty()trong trường hợp bạn không. Bạn không bao giờ ném 2 và không bao giờ quay trở lại null.

Đối với khách hàng của phương thức của bạn, nó là một cái gì đó giống như null, nhưng với sự khác biệt lớn mà nó buộc phải suy nghĩ về trường hợp thiếu các mặt hàng. Người dùng không thể đơn giản bỏ qua thực tế là có thể không có kết quả. Để đưa mục ra khỏi Optionalmột hành động rõ ràng là bắt buộc:

  • loadItem(1).get()sẽ ném một NoSuchElementExceptionhoặc trả lại các mặt hàng tìm thấy.
  • Ngoài ra còn có loadItem(1).orElseThrow(() -> new MyException("No item 1"))một ngoại lệ tùy chỉnh nếu trả về Optionaltrống.
  • loadItem(1).orElse(defaultItem)trả về vật phẩm tìm thấy hoặc vật phẩm đã qua defaultItem(cũng có thể là null) mà không ném ngoại lệ.
  • loadItem(1).map(Item::getName)sẽ một lần nữa trả lại một Optionalvới tên các mặt hàng, nếu có.
  • Có một số phương thức khác, xem Javadoc choOptional .

Ưu điểm là bây giờ tùy thuộc vào mã máy khách, điều gì sẽ xảy ra nếu không có mục nào và bạn vẫn chỉ cần cung cấp một phương thức duy nhất .


1 Tôi đoán nó giống như câu trả lờitry? trong gnasher729 nhưng nó không hoàn toàn rõ ràng đối với tôi vì tôi không biết Swift và nó dường như là một tính năng ngôn ngữ nên nó đặc trưng cho Swift.

2 Bạn có thể đưa ra các ngoại lệ vì các lý do khác, ví dụ: nếu bạn không biết liệu có một mục hay không vì bạn gặp vấn đề khi giao tiếp với cơ sở dữ liệu.


0

Như một điểm khác đồng ý với việc sử dụng hai phương pháp, điều này có thể rất dễ thực hiện. Tôi sẽ viết ví dụ của mình bằng C #, vì tôi không biết cú pháp của PHP.

public Widget GetWidgetOrNull(int id) {
    // All the lines to get your item, returning null if not found
}

public Widget GetWidget(int id) {
    var widget = GetWidgetOrNull(id);

    if (widget == null) {
        throw new WidgetNotFoundException();
    }

    return widget;
}

0

Tôi thích hai phương thức, theo cách này, bạn sẽ không chỉ cho tôi biết bạn đang trả về một giá trị, mà là giá trị chính xác.

public int GetValue(); // If you can't get the value, you'll throw me an exception
public int GetValueOrDefault(); // If you can't get the value, you'll return me 0, since it's the default for ints

TryDoSthing () cũng không phải là một mẫu xấu.

public bool TryParse(string value, out int parsedValue); // If you return me false, I won't bother checking parsedValue.

Tôi thường sử dụng để thấy cái trước trong các tương tác cơ sở dữ liệu trong khi cái sau được sử dụng nhiều hơn trong các công cụ phân tích cú pháp.

Như những người khác đã nói với bạn, các tham số cờ thường là mùi mã (mùi mã không có nghĩa là bạn đang làm gì đó sai, chỉ có xác suất là bạn đang làm sai). Mặc dù bạn đặt tên chính xác, đôi khi có những sắc thái khó biết cách sử dụng cờ đó và cuối cùng bạn nhìn vào bên trong thân phương thức.


-1

Mặc dù những người khác đề nghị khác, tôi sẽ đề nghị rằng có một phương thức với tham số để chỉ ra cách xử lý lỗi sẽ tốt hơn so với yêu cầu sử dụng các phương thức riêng biệt cho hai kịch bản sử dụng. Trong khi nó có thể được mong muốn để cũng có điểm vào riêng biệt cho các "lỗi ném" so với "dấu hiệu cho thấy lợi nhuận error error" tập quán, có một điểm mấu chốt có thể phục vụ cả hai mô hình sử dụng sẽ tránh trùng lặp mã trong phương pháp wrapper. Ví dụ đơn giản, nếu ai có chức năng:

Thing getThing(string x);
Thing tryGetThing (string x);

và người ta muốn các hàm hoạt động tương tự nhưng với x được bao trong ngoặc, cần phải viết hai bộ hàm bao bọc:

Thing getThingWithBrackets(string x)
{
  getThing("["+x+"]");
}
Thing tryGetThingWithBrackets (string x);
{
  return tryGetThing("["+x+"]");
}

Nếu có một đối số về cách xử lý lỗi, chỉ cần một trình bao bọc:

Thing getThingWithBrackets(string x, bool returnNullIfFailure)
{
  return getThing("["+x+"]", returnNullIfFailure);
}

Nếu trình bao bọc đủ đơn giản, việc sao chép mã có thể không quá tệ, nhưng nếu có thể cần phải thay đổi, việc sao chép mã sẽ lần lượt yêu cầu sao chép bất kỳ thay đổi nào. Ngay cả khi một người chọn để thêm điểm vào mà không sử dụng đối số phụ:

Thing getThingWithBrackets(string x)
{
   return getThingWithBrackets(x, false);
}
Thing tryGetThingWithBrackets(string x)
{
   return tryGetThingWithBrackets(x, true);
}

người ta có thể giữ tất cả "logic kinh doanh" trong một phương thức - một phương thức chấp nhận một đối số chỉ ra những việc cần làm trong trường hợp thất bại.


Bạn đã đúng: Trình trang trí và trình bao bọc, và thậm chí thực hiện thường xuyên, sẽ có một số sao chép mã khi sử dụng hai phương thức.
donquixote

Chắc chắn đặt các phiên bản có và không có ngoại lệ - ném vào các gói riêng biệt, và làm cho các hàm bao chung chung?
Sẽ Crawford

-1

Tôi nghĩ rằng tất cả các câu trả lời giải thích rằng bạn không nên có một lá cờ kiểm soát xem một ngoại lệ có được ném hay không là tốt. Lời khuyên của họ sẽ là lời khuyên của tôi cho bất cứ ai cảm thấy cần phải hỏi câu hỏi đó.

Tôi đã làm, tuy nhiên, muốn chỉ ra rằng có một ngoại lệ có ý nghĩa đối với quy tắc này. Khi bạn đủ tiến bộ để bắt đầu phát triển API mà hàng trăm người khác sẽ sử dụng, có những trường hợp bạn có thể muốn cung cấp một cờ như vậy. Khi bạn đang viết một API, bạn không chỉ viết cho những người theo chủ nghĩa thuần túy. Bạn đang viết thư cho những khách hàng thực sự có ham muốn thực sự. Một phần công việc của bạn là làm cho họ hài lòng với API của bạn. Điều đó trở thành một vấn đề xã hội, thay vì một vấn đề lập trình, và đôi khi các vấn đề xã hội chỉ ra các giải pháp ít lý tưởng hơn là các giải pháp lập trình.

Bạn có thể thấy rằng bạn có hai người dùng API riêng biệt, một trong số họ muốn có ngoại lệ và một người không có ngoại lệ. Một ví dụ thực tế trong đó điều này có thể xảy ra là với một thư viện được sử dụng cả trong phát triển và trên một hệ thống nhúng. Trong môi trường phát triển, người dùng có thể sẽ muốn có ngoại lệ ở mọi nơi. Các ngoại lệ rất phổ biến để xử lý các tình huống bất ngờ. Tuy nhiên, chúng bị cấm trong nhiều tình huống nhúng vì chúng quá khó để phân tích các ràng buộc thời gian thực xung quanh. Khi bạn thực sự quan tâm không chỉ là thời gian trung bình cần thiết để thực hiện chức năng của mình, mà là thời gian cần thiết cho bất kỳ một niềm vui riêng lẻ nào, ý tưởng tháo gỡ ngăn xếp tại bất kỳ vị trí tùy ý nào là rất không mong muốn.

Một ví dụ thực tế cho tôi: một thư viện toán học. Nếu thư viện toán học của bạn có một Vectorlớp hỗ trợ nhận một vectơ đơn vị theo cùng một hướng, bạn phải có thể chia cho độ lớn. Nếu cường độ bằng 0, bạn có một chia cho tình huống bằng không. Trong sự phát triển bạn muốn bắt những thứ này . Bạn thực sự không muốn chia đáng ngạc nhiên cho 0 xung quanh. Ném một ngoại lệ là một giải pháp rất phổ biến cho việc này. Nó gần như không bao giờ xảy ra (đó là hành vi thực sự đặc biệt), nhưng khi nó xảy ra, bạn muốn biết điều đó.

Trên nền tảng nhúng, bạn không muốn những ngoại lệ đó. Nó sẽ có ý nghĩa hơn để làm một kiểm tra if (this->mag() == 0) return Vector(0, 0, 0);. Trong thực tế, tôi thấy điều này trong mã thực.

Bây giờ nghĩ từ quan điểm của một doanh nghiệp. Bạn có thể thử dạy hai cách sử dụng API khác nhau:

// Development version - exceptions        // Embeded version - return 0s
Vector right = forward.cross(up);          Vector right = forward.cross(up);
Vector localUp = right.cross(forward);     Vector localUp = right.cross(forward);
Vector forwardHat = forward.unit();        Vector forwardHat = forward.tryUnit();
Vector rightHat = right.unit();            Vector rightHat = right.tryUnit();
Vector localUpHat = localUp.unit()         Vector localUpHat = localUp.tryUnit();

Điều này thỏa mãn ý kiến ​​của hầu hết các câu trả lời ở đây, nhưng từ góc độ công ty thì điều này là không mong muốn. Các nhà phát triển nhúng sẽ phải học một kiểu mã hóa và các nhà phát triển phát triển sẽ phải học một kiểu khác. Điều này có thể khá phiền phức và buộc mọi người phải suy nghĩ một cách. Có khả năng tệ hơn: làm thế nào để bạn chứng minh rằng phiên bản nhúng không bao gồm bất kỳ mã ném ngoại lệ nào? Phiên bản ném có thể dễ dàng hòa trộn, ẩn ở đâu đó trong mã của bạn cho đến khi Hội đồng Đánh giá Thất bại đắt tiền tìm thấy nó.

Mặt khác, nếu bạn có một cờ bật hoặc tắt xử lý ngoại lệ, cả hai nhóm có thể học cùng một kiểu mã hóa chính xác. Trong thực tế, trong nhiều trường hợp, bạn thậm chí có thể sử dụng mã của một nhóm trong các dự án của nhóm khác. Trong trường hợp sử dụng mã này unit(), nếu bạn thực sự quan tâm đến những gì xảy ra trong phép chia cho 0, bạn nên tự mình viết bài kiểm tra. Do đó, nếu bạn di chuyển nó sang một hệ thống nhúng, nơi bạn vừa nhận được kết quả xấu, thì hành vi đó là "lành mạnh". Bây giờ, từ góc độ kinh doanh, tôi đào tạo các lập trình viên của mình một lần và họ sử dụng cùng các API và cùng một phong cách trong tất cả các phần của doanh nghiệp của tôi.

Trong phần lớn các trường hợp, bạn muốn làm theo lời khuyên của người khác: sử dụng các thành ngữ giống tryGetUnit()hoặc tương tự cho các hàm không đưa ra ngoại lệ và thay vào đó trả về giá trị sentinel như null. Nếu bạn nghĩ rằng người dùng có thể muốn sử dụng cả mã xử lý ngoại lệ và mã xử lý không ngoại lệ cạnh nhau trong một chương trình, hãy sử dụng tryGetUnit()ký hiệu. Tuy nhiên, có một trường hợp góc mà thực tế kinh doanh có thể làm cho nó tốt hơn để sử dụng cờ. Nếu bạn thấy mình trong trường hợp góc đó, đừng ngại ném "quy tắc" bên đường. Đó là những quy tắc dành cho!

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.