2010-03-05 24 views
5

Hãy xem xét các lớp saucó nên phương pháp lớp chấp nhận các tham số hoặc thuộc tính của lớp sử dụng

public class Class1 
{ 
    public int A { get; set; } 
    public int B { get; set; } 

    public int GetComplexResult() 
    { 
     return A + B; 
    } 
} 

Để sử dụng GetComplexResult, một người tiêu dùng của lớp này sẽ phải biết để thiết lập AB trước khi gọi phương pháp này. Nếu GetComplexResult truy cập nhiều thuộc tính để tính kết quả của nó, điều này có thể dẫn đến các giá trị trả về sai nếu người tiêu dùng không đặt tất cả các thuộc tính thích hợp trước tiên. Vì vậy, bạn có thể viết lớp này như thế này thay vì

public class Class2 
{ 
    public int A { get; set; } 
    public int B { get; set; } 

    public int GetComplexResult(int a, int b) 
    { 
     return a + b; 
    } 
} 

Bằng cách này, một người gọi đến GetComplexResult buộc phải vượt qua trong tất cả các giá trị cần thiết, đảm bảo giá trị lợi nhuận kỳ vọng được tính một cách chính xác. Nhưng nếu có nhiều giá trị cần thiết, danh sách tham số sẽ tăng lên và điều này dường như không có thiết kế tốt. Nó cũng có vẻ phá vỡ các điểm đóng gói A, BGetComplexResult trong một lớp duy nhất. Tôi thậm chí có thể bị cám dỗ để làm cho GetComplexResult tĩnh vì nó không yêu cầu một cá thể của lớp để thực hiện công việc của nó. Tôi không muốn đi xung quanh thực hiện một loạt các phương pháp tĩnh.

Có các thuật ngữ để mô tả 2 cách tạo lớp khác nhau này không? Cả hai dường như có ưu và khuyết điểm - có điều gì đó tôi không hiểu nên nói với tôi rằng một cách nào đó tốt hơn cách khác? Thử nghiệm đơn vị ảnh hưởng đến lựa chọn này như thế nào?

Trả lời

5

Nếu bạn sử dụng ví dụ trong thế giới thực, câu trả lời sẽ trở nên rõ ràng hơn.

public class person 
{ 
    public string firstName { get; set; } 
    public string lastName { get; set; } 

    public string getFullName() 
    { 
     return firstName + " " + lastName; 
    } 
} 

Mấu chốt của một đối tượng thực thể là nó chứa thông tin về một tổ chức nào, và có thể làm những hoạt động mà các tổ chức cần phải làm gì (dựa trên thông tin mà nó chứa). Vì vậy, có, có những tình huống trong đó một số hoạt động sẽ không hoạt động đúng bởi vì thực thể chưa được khởi tạo đầy đủ, nhưng đó không phải là một thất bại của thiết kế. Nếu, trong thế giới thực, tôi yêu cầu bạn cho tên đầy đủ của một em bé sơ sinh chưa được nêu tên, điều đó cũng sẽ thất bại.

Nếu một số thuộc tính cần thiết cho một thực thể thực hiện công việc của mình, chúng có thể được khởi tạo trong một hàm tạo. Một cách khác là phải có một boolean để kiểm tra liệu các thực thể đang trong tình trạng nơi một phương pháp nhất định có thể được gọi là:

while (person.hasAnotherQuestion()) { 
    person.answerNextQuestion(); 
} 
+0

Tôi luôn cố gắng gọi getters thay vì truy cập trực tiếp các thành viên, và trong getter tôi đăng nhập một thông báo nếu tôi trả về giá trị null. Tôi đã từng sử dụng các xác nhận, nhưng sau đó chúng tôi phát hiện ra rằng một số khách hàng của chúng tôi chạy với các xác nhận được bật trong sản xuất (!). – TMN

1

Một nguyên tắc thiết kế tốt là để đảm bảo rằng tất cả các nhà xây dựng khởi đối tượng để các quốc gia hợp lệ và rằng tất cả các hàm và phương thức thuộc tính sau đó thực thi trạng thái hợp lệ. Bằng cách này sẽ không bao giờ có bất kỳ đối tượng nào ở trạng thái không hợp lệ.

Nếu các giá trị mặc định cho AB, đó là 0 không phải là một nhà nước hợp lệ mà mang lại một kết quả có giá trị từ GetComplexResult, bạn nên một constructor mà khởi AB đến tình trạng hợp lệ.

0

Nếu một số trường không bao giờ được phép là rỗng thì bạn thường sẽ tạo các tham số cho hàm tạo lớp. Nếu bạn không luôn luôn có tất cả các giá trị cần thiết có sẵn cùng một lúc thì sử dụng lớp trình tạo có thể hữu ích.

Ví dụ:

public Builder { 
    private int a; 
    private int b; 

    public Class1 create() { 
     // some validation logic goes here 
     // to make sure we have everything and 
     // either fill in defaults or throw an error 
     // if needed 
     return new Class1(a, b) 
    } 

    public Builder a(int val) { a = val; } 
    public Builder b(int val) { b = val; } 
} 

Builder này sau đó có thể được sử dụng như sau.

Class1 obj1 = new Builder().a(5).b(6).create(); 

Builder builder = new Builder(); 
// do stuff to find value of a 
builder.a(valueOfA); 
// do stuff to find value of b 
builder.b(valueOfB); 
// do more stuff 
Class1 obj2 = builder.create(); 
Class2 obj3 = builder.create(); 

Thiết kế này cho phép bạn khóa các lớp Thực thể ở bất kỳ mức độ nào phù hợp trong khi vẫn cho phép quá trình xây dựng linh hoạt. Nó cũng mở ra cánh cửa để tùy chỉnh quá trình xây dựng với các triển khai khác mà không thay đổi hợp đồng lớp thực thể.

Các vấn đề liên quan