2010-01-20 8 views
24

Hãy có một đối tượng được tạo ra trong một getter như thế này:Có phải việc tạo đối tượng trong thực hành xấu không?

public class Class1 
{ 
     public string Id { get; set; } 
     public string Oz { get; set; } 
     public string Poznamka { get; set; } 

     public Object object 
     { 
      get 
      { 
        // maybe some more code 
        return new Object { Id = Id, poznamla = Poznamka, Oz = OZ }; 
      } 
     } 
} 

Hoặc tôi nên thay vì tạo ra một phương pháp mà sẽ tạo ra và trả lại đối tượng?

Trả lời

14

Thuộc tính trông giống như các trường nhưng chúng là phương pháp. Điều này đã được biết là gây ra một sự nhầm lẫn phi thường. Khi một lập trình viên nhìn thấy mã dường như đang truy cập một trường, có nhiều giả định rằng lập trình viên làm cho điều đó có thể không đúng đối với một thuộc tính. Do đó, có một số hướng dẫn thiết kế đặc tính chung.

  1. Tránh trả lại các giá trị khác nhau từ bộ nạp tài sản. Nếu được gọi nhiều lần trong một hàng, một phương thức thuộc tính có thể trả về một giá trị khác nhau mỗi lần; một trường trả về cùng một giá trị mỗi lần.

  2. Phương pháp thuộc tính có thể yêu cầu bộ nhớ bổ sung hoặc trả về tham chiếu đến một thứ không thực sự là một phần của trạng thái của đối tượng, vì vậy việc sửa đổi đối tượng trả về không ảnh hưởng đến đối tượng ban đầu; truy vấn một trường luôn trả về một tham chiếu đến một đối tượng được đảm bảo là một phần của trạng thái của đối tượng gốc. Làm việc với một thuộc tính trả về một bản sao có thể rất khó hiểu đối với các nhà phát triển và đặc tính này thường không được ghi lại.

  3. Hãy xem xét rằng thuộc tính không được chuyển thành tham số ra hoặc tham số cho phương thức; một trường có thể.

  4. Tránh sử dụng getters thuộc tính chạy dài. Một phương thức thuộc tính có thể mất nhiều thời gian để thực thi; truy cập trường luôn hoàn thành ngay lập tức.

  5. Tránh ném ngoại lệ từ getters.

  6. Do bảo tồn giá trị trước đó nếu một setter sở hữu ném một ngoại lệ

  7. tác dụng phụ có thể quan sát Tránh.

  8. Cho phép các thuộc tính được đặt theo bất kỳ thứ tự nào ngay cả khi điều này dẫn đến trạng thái tạm thời không hợp lệ của các đối tượng.

Nguồn

"CLR via C#", Jeffrey Richter. Chương 9. Xác định tính thông minh

"Framework Design Guidelines" 2nd edition, Brad Abrams, Krzysztof Cwalina, Chương 5.2 Thiết kế tài sản

22

Vâng, thực tiễn không tốt.

Lý tưởng nhất, người thay thế không nên thay đổi hoặc tạo ra bất kỳ thứ gì (ngoài việc tải xuống lười biếng, và thậm chí sau đó tôi nghĩ nó dẫn đến mã ít rõ ràng hơn ...). Bằng cách đó bạn giảm thiểu nguy cơ tác dụng phụ không chủ ý.

+0

Vậy điều gì là tốt cho họ? – user137348

+2

có thể sử dụng trường – user137348

+1

Các thuộc tính cho phép bạn trả về các giá trị phòng hộ, ví dụ, chuyển một cuộc gọi đến Đếm đến một biến trong lớp (ví dụ: trả về m_Collection.Count) – thecoop

8

Nếu bạn muốn người khởi động tạo đối tượng mới mỗi lần truy cập, đó là cách thực hiện. Mẫu này thường được gọi là Factory Method.

Tuy nhiên, điều này thường không cần thiết đối với các thuộc tính (ví dụ: getters và setters), và như vậy được coi là thực hành không tốt.

+1

Điều đó có nghĩa là bạn sẽ có được một đối tượng khác nhau mỗi khi bạn truy cập trình khởi động; chắc chắn là một ý tưởng tồi! –

+0

Hm, khi tôi đọc điều này, có vẻ như bạn đang nói rằng sử dụng mẫu Phương thức Nhà máy là thực hành không tốt. Theo tôi, điều đó không thực sự đúng. Tuy nhiên, bằng cách sử dụng mẫu phương thức nhà máy cho getters và setters là một thực tế không tốt. – Fortega

+0

@Mitch - Tôi đồng ý. Trừ khi đó là chính xác những gì bạn cần ... – Oded

0

Nó có thể được chấp nhận nhiều nhất cho struct s. Đối với các loại tài liệu tham khảo, tôi sẽ chỉ tạo một đối tượng mới trong một getter khi nó chỉ được thực hiện khi sử dụng một số mẫu tải lười.

0

Nó phụ thuộc vào việc sử dụng bộ thu sóng. Đó là một nơi tuyệt vời để bao gồm loại mã này để tải chậm.

2

Một thuộc tính nên, cho mọi mục đích và mục đích, hoạt động như một trường. Điều đó có nghĩa là không có ngoại lệ nên được ném và không có đối tượng mới nào được tạo (do đó bạn không tạo nhiều đối tượng không cần thiết nếu thuộc tính được sử dụng trong vòng lặp)

Sử dụng lớp bọc hoặc thay thế tương tự.

0

Thực tiễn không tốt. Trong ví dụ của bạn, bạn sẽ có thể mong đợi cùng một Object mỗi lần bạn truy cập vào thuộc tính object.

0

Thực tiễn không tốt. Nhưng nếu bạn đang suy nghĩ về các đối tượng như một loạt các getters & setters bạn nên kiểm tra các cuộc thảo luận cổ điển về chủ đề.

Như một số người đã đề cập, việc tải chậm có thể là lý do để làm như vậy. Phụ thuộc vào logic kinh doanh thực tế mà bạn đang lập mô hình ở đây. Bạn nên tạo một phương thức riêng biệt nếu nó là tốt hơn cho các mục đích dễ đọc, nhưng nếu mã để tạo đối tượng là đơn giản, bạn có thể tránh được sự gián đoạn.

4

có, nó là ... từ bên ngoài, nó cần phải minh bạch, cho dù bạn truy cập vào một tài sản hoặc một lĩnh vực ...

khi đọc hai lần từ trường, hoặc một tài sản, bạn mong đợi hai điều:

  • không có ảnh hưởng đến hành vi (bên ngoài) của đối tượng
  • bạn sẽ có được kết quả giống hệt

tôi không có kiến ​​thức thực tế của C#, nhưng tôi hy vọng, sự làm cho sau quan điểm của tôi rõ ràng.hãy bắt đầu như thế này:

Object o1 = myInst.object; 
Object o2 = myInst.object; 
o1.poznamka = "some note"; 

trong trường hợp của một trường, các điều kiện như sau đây sẽ là sự thật:

o1 == o2; 
o2.poznamka == "some note"; 

nếu bạn sử dụng một tài sản với một getter, mà trả về một đối tượng mới mỗi lần được gọi là, cả hai điều kiện sẽ là sai ...

trình thu thập của bạn dường như có nghĩa là tạo ra ảnh chụp tạm thời về cá thể của bạn ... nếu đó là những gì bạn muốn, hơn là làm cho nó trở thành một phương thức đơn giản ... tránh bất kỳ sự mơ hồ nào ...

2

Theo tôi nếu một cái gì đó là 'tài sản' getter sẽ trả lại cho bạn một tài sản (về cơ bản là một dữ liệu đã tồn tại) có liên quan đến đối tượng.

Trong trường hợp của bạn, bạn đang trả lại thứ gì đó không phải là tài sản của đối tượng đó tại thời điểm đó. Bạn không trả lại tài sản của đối tượng của bạn mà là một sản phẩm của một số hành động.

Tôi sẽ sử dụng phương thức GetMyObject() thay thế. Đặc biệt nếu có một 'hành động' sẽ diễn ra, tôi nghĩ rằng hầu hết thời gian tốt nhất để có một phương pháp hơn là một tài sản tên.

Và hãy thử tưởng tượng những nhà phát triển khác nào không quen thuộc với mã của bạn mong đợi sau khi xem thuộc tính của bạn.

1

Thuộc tính chỉ là cách thuận tiện để thể hiện trường được tính toán.

Nó vẫn phải đại diện cho một cái gì đó về một đối tượng, bất kể giá trị của chính nó đến như thế nào. Ví dụ: nếu đối tượng được đề cập là hóa đơn, bạn có thể phải tăng thêm chi phí của từng chi tiết đơn hàng và trả lại tổng số.

Nội dung được viết trong câu hỏi ngắt quy tắc đó, bởi vì trả lại bản sao của đối tượng không phải là nội dung mô tả đối tượng. Nếu giá trị trả về thay đổi giữa các cuộc gọi đến thuộc tính mà không thay đổi rõ ràng trạng thái đối tượng, thì mô hình đối tượng bị hỏng.

Nói chung, trả về một đối tượng mới như thế này sẽ luôn luôn phá vỡ quy tắc (tôi không thể nghĩ ra một ví dụ ngược), vì vậy tôi sẽ nói rằng đó là thực hành không tốt.

Ngoài ra còn có các đặc tính của nơi bạn có thể dễ dàng và ngây thơ gọi trên một thuộc tính nhiều lần và kết thúc chạy cùng một mã (mà hy vọng không phải là chậm!).

1

Đối với văn bản mã mà có thể dễ dàng kiểm tra, bạn phải duy trì tách đối tượng khởi tạo.

tức là trong các trường hợp thử nghiệm bạn không có thử nghiệm một số mặt hàng cụ thể.

như trong đối tượng Nhà bạn không muốn kiểm tra bất kỳ điều gì liên quan đến đối tượng nhà bếp. và bạn chỉ thử nghiệm khu vườn. vì vậy trong khi bạn bắt đầu một lớp nhà và bắt đầu đối tượng trong một số nhà xây dựng hoặc trong getters bạn sẽ không được mã hóa tốt mà sẽ hỗ trợ thử nghiệm.

1

Là một sang một bên các bình luận đã được thực hiện, bạn có thể chạy vào một số nhức đầu gỡ lỗi thực sự khi các trường tải lười biếng thông qua một tài sản.

Tôi đã có một lớp học với

private Collection<int> moo; 

public Collection<int> Moo 
{ 
    get 
    { 
    if (this.moo == null) this.moo = new Collection<int>(); 
    return this.moo; 
    } 
} 

Sau đó, ở một nơi khác trong lớp có một phương pháp nào đó tham chiếu

this.moo.Add(baa); 

mà không kiểm tra nó đã được khởi tạo.

Nó đã ném một ngoại lệ tham chiếu null, như mong đợi. Nhưng ngoại lệ là trên một chuỗi giao diện người dùng nên không ngay lập tức rõ ràng nó đến từ đâu. Tôi bắt đầu truy tìm thông qua, và mỗi khi tôi truy tìm thông qua, các lỗi biến mất.

Trong một thời gian, tôi phải thừa nhận rằng mình đã phát điên. Trình gỡ lỗi - không có lỗi. Lỗi runtime.Nhiều gãi đầu sau này tôi phát hiện lỗi, và nhận ra rằng Trình gỡ lỗi Visual Studio đã khởi tạo Bộ sưu tập khi nó hiển thị các thuộc tính công khai của lớp.