2014-04-02 17 views
12

Tôi đang cố gắng tìm ra những ưu điểm và nhược điểm của một phương thức có nhiều giá trị kết quả.Giá trị trả về thực hành tốt nhất so với ngoại lệ và Enum

Ví dụ: tôi đang sử dụng phương thức đăng nhập. Nếu thông tin đăng nhập thành công, thông tin đăng nhập sẽ vượt qua, nếu không tôi cần biết tại sao nó không thành công.

1. Trở đúng hay sai (Không đủ thông tin)

bool Login(string user, string password); 

2. Trở thành sự thật, nếu nó đã thành công, nếu không ném một ngoại lệ

public class UnknownUserException : Exception { } 
public class WrongPasswordException : Exception { } 
bool Login(string user, string password); 

3. Không trả lại gì cả. Ném một ngoại lệ, nếu nó đã không thành công

public class UnknownUserException : Exception { } 
public class WrongPasswordException : Exception { } 
void Login(string user, string password); 

4. Return một giá trị enum

enum LoginResult 
{ 
    Successful 
    UnknownUser, 
    WrongPassword 
} 
LoginResult Login(string user, string password); 

"Đăng nhập" chỉ là một ví dụ như vậy. Tôi muốn biết những ưu điểm và nhược điểm của việc triển khai khác nhau là gì, và trong trường hợp nào thì chúng ít nhiều thích hợp.

+0

1 và 2 là rõ ràng không đáng được quan tâm. # 3 là trong tĩnh mạch của cách mọi thứ thường được thực hiện, nhưng người duy nhất được trang bị để nhận ra rằng có lẽ # 4 là thích hợp hơn trong trường hợp của bạn là bạn. – Jon

+0

API là đồng bộ hoặc không đồng bộ? –

+0

đồng bộ, xin lỗi :) – Jan

Trả lời

3

Bạn sẽ nhận được nhiều câu trả lời theo ý kiến ​​hơn, Nếu tôi đang thực hiện, tôi sẽ kết hợp 3 & 4. Ném LoginFailedException bằng enum nói lý do.

void Login(string user, string password);//Or return a bool(redundant though) 

class LoginFailedException : ApplicationException 
{ 
    public LoginFailReason Reason {get; private set;} 
    public LoginFailedException(LoginFailReason reason) 
    { 
     this.Reason = reason; 
    } 
} 

enum LoginFailReason 
{ 
    UnknownUser, 
    WrongPassword 
} 

Lý do để lựa chọn ngoại lệ tùy chọn: Giả sử bạn chọn giá trị trả về chỉ tiếp cận, người sử dụng api của bạn (có thể khách hàng, hoặc các nhà phát triển khác) có thể nhận được một cơ hội để bỏ qua API.

instance.Login(user, password); 
var accountInfo = instance.GetAccountInfo();//Assuming logged in; going to explode 

Ai biết được họ phải làm như thế này

if(instance.Login(user, password) == LoginResult.Successful)) 
{ 
    var accountInfo = instance.GetAccountInfo(); 
} 

Vì vậy, ngoại lệ IMO ném vào mặt nói tôi không thể xử lý yêu cầu đăng nhập của bạn vì lý do như vậy và như vậy. Làm cho nó đơn giản.

+4

Tôi thích cách tiếp cận này, mặc dù cảm thấy sai khi ném một ngoại lệ vào cái gì, imho, có vẻ như một điểm chung kịch bản. Tôi cảm thấy Ngoại lệ nên được sử dụng trong các kịch bản 'ngoại lệ' khi có điều gì đó sai ở mức độ sâu hơn. – Moeri

+2

@Moeri Tôi tin rằng đây là cách đúng đắn, đăng nhập thất bại không phải là điều kiện bình thường mà nó là một điều kiện ** đặc biệt **, bạn nên chọn một ứng dụng Enum, và bạn phát triển API công khai, nếu người dùng không làm gì t kiểm tra giá trị trả về và chỉ cần gọi 'Login();' và giả định đăng nhập.? Ném nó vào mặt nói heyy một cái gì đó đã đi sai (giống như sqlserver không thông qua SqlException) –

+0

@Moeri Ngoại lệ là có để thay thế 'C-Style' mã trạng thái và' GetLastError() 's. Làm thế nào bạn sẽ thực hiện ý tưởng của 'Ngoại lệ bên trong' với cách tiếp cận đó? * trường hợp khi lỗi xảy ra hai hoặc nhiều lớp * – tchelidze

1

Chắc chắn không phải là ngoại lệ. Đăng nhập không thành công hầu như không phải là một trường hợp "đặc biệt" và nó chỉ là một quá trình logic bình thường cho ứng dụng. Nếu bạn sử dụng một ngoại lệ thì bạn sẽ luôn luôn phải đăng nhập bằng một trình xử lý ngoại lệ mà không có lý do nào khác ngoài việc xử lý trường hợp đăng nhập thất bại. Điều đó có vẻ giống như định nghĩa của việc sử dụng các ngoại lệ cho luồng logic, điều này không đúng.

Nếu bạn cần trả lại thông tin cụ thể (không phải là luôn cần cần thiết từ chức năng đăng nhập, nhưng có thể trong trường hợp của bạn), # 4 có vẻ hợp lý. Bạn có thể tiến thêm một bước nữa và biến nó thành một đối tượng:

public class LoginResult 
{ 
    // an enum for the status 
    // a string for a more specific message 
    // a valid user object on successful login 
    // etc. 
} 

Hoặc tùy thuộc vào logic, cấu trúc không thay đổi thay vì một lớp. (Hãy chắc chắn rằng cấu trúc là bất biến, cấu trúc có thể thay đổi được chỉ yêu cầu cho rắc rối.) Điểm là bạn có thể áp dụng tất cả các loại logic và chức năng trên đối tượng kết quả chính nó, mà dường như là hướng bạn đang hướng.

1

Tất nhiên nó phụ thuộc vào tình huống cụ thể nhưng hãy để tôi cung cấp một vài ý kiến ​​chủ quan của tôi ở đây:

  1. Tôi chắc chắn những trường hợp này cần phải tránh. Tên của phương thức chỉ ra rằng nó chỉ thực hiện bất kỳ thao tác nào như "Đăng nhập". Theo tên phương pháp, chúng tôi không thể mong đợi bất kỳ kết quả nào ở đây. Bạn có muốn trả lại giá trị bool tốt hơn không nếu đặt tên là IsLoggedIn(userName). Ngoài ra, bạn sẽ không bao giờ biết nếu bạn cần mở rộng tập các giá trị được trả về. Vì vậy, enum tốt hơn nhiều ở đây cũng tính đến mục đích của giá trị được phản ánh trong tên enum thay vì đơn giản bool.

  2. Tương tự như trên. Các ngoại lệ ở đây giúp ngăn chặn toàn bộ hệ thống phân cấp thực thi (tất nhiên có thể chứa nhiều hơn 1 phương thức trong ngăn xếp cuộc gọi) thay vì chỉ trả về kết quả và để người gọi đưa ra quyết định phù hợp. Giải pháp linh hoạt hơn cho tôi. Trong trường hợp hiện tại, tôi chỉ sử dụng ngoại lệ để xác thực thông số. Các tình huống như "tên người dùng/mật khẩu sai" không phải là ngoại lệ. Họ là bình thường từ các trường hợp sử dụng quan điểm. Tham số null hoặc tham số sai là trường hợp ngoại lệ.

  3. Nếu bạn không cần phương thức trả về giá trị, đó là cách để thực hiện. Đừng quên bạn không nên sử dụng ngoại lệ như một điều hướng. Ý tôi là UserSuccessfullyCreatedException hoặc hơn thế.

  4. Như tôi đã đề cập ở trên, đó là cách tốt nhất cho tôi. Điểm duy nhất không phải là đặt các ngoại lệ xác nhận là một giá trị enum. Bạn có ngoại lệ cho nó.

Vì vậy, enum kết quả cộng với trường hợp ngoại lệ để xác thực là một cách để đi.

Nếu bạn muốn thu thập tất cả các lỗi trong quá trình thực phương pháp có thể bạn sẽ muốn tạo đặc biệt LoginOperationResult lớp để bọc tất cả các thông tin (bao gồm xác nhận errors` xảy ra trong quá trình thực phương pháp.

class OperationResult 
{ 
    public OperationStatus Status { get; set; } 

    public IEnumerable<ValidationError> Errors { get; set; } 
    // or list of exceptions 
} 

class LoginOperationResult : OperationResult 
{ 
    // Login result specific data. 
} 

enum OperationStatus 
{ 
    Success, 
    Denied, 
    ValidationFailed, 
    // etc. 
} 
0

tôi thường sử dụng phương pháp này trong các dự án của tôi:

chữ ký:

bool TryLogin(string username, string password, out User user); 

sử dụng:

User user; 
if(userService.TryLogin(username, password, out user))) 
{ 
    // do stuff with user 
} 
else 
{ 
    // show "login failed" 
} 

Bạn có thể mở rộng này để trả lại Enum của bạn:

chữ ký:

enum LoginResult 
{ 
    Successful 
    UnknownUser, 
    WrongPassword 
} 

LoginResult TryLogin(string username, string password, out User user); 

sử dụng:

User user; 
LoginResult loginResult; 
if((loginResult = userService.TryLogin(username, password, out user)) == LoginResult.Successful) 
{ 
    // do stuff with user 
} 
else 
{ 
    // do stuff with loginResult 
} 
Các vấn đề liên quan