2012-09-24 33 views
7

Folks,Java - Clone tài sản bên trong phương thức getter

tôi đang trải qua thực hành mã hóa tốt nhất của Java đề cập ở đây
http://viralpatel.net/blogs/most-useful-java-best-practice-quotes-java-developers/

quote thứ 2 nói,

Trích 2: Không bao giờ thực hiện một các trường mẫu của lớp công khai

Tôi đồng ý điều đó hoàn toàn chính xác, nhưng tôi đã bị mắc kẹt với những lời giới thiệu của nhà văn sau vài dòng bên dưới câu nói này.

Ông nói,


private String[] weekdays = 
    {"Sun", "Mon", "Tue", "Thu", "Fri", "Sat", "Sun"}; 

public String[] getWeekdays() { 
    return weekdays; 
} 

Nhưng viết phương thức getter không chính xác giải quyết vấn đề của chúng tôi. Mảng vẫn có thể truy cập được. Cách tốt nhất để làm cho nó không thể sửa đổi là trả về một bản sao của mảng thay vì mảng chính nó. Do đó, phương thức getter sẽ được thay đổi để

public String[] getWeekdays() { 
    return weekdays.clone(); 
} 

Tôi chưa bao giờ bản thân mình sử dụng clone() bên trong bất kỳ phương thức getter của lớp Java.

tôi tự hỏi (như nó được đề cập đến là một trong những thực hành tốt) - tại sao người ta should use/shouldn't useclone() bên trong phương thức getter? và trong kịch bản nào?

Google có đủ điều kiện để trở thành một thực hành mã hóa tốt cho Java không?

Cảm ơn

+2

IMO - Đối với các đối tượng không thể thay đổi và bản sao loại dữ liệu nguyên thủy là không bắt buộc. Đối với mọi thứ khác nếu chúng tôi thực sự muốn dữ liệu của chúng tôi được an toàn, chúng tôi phải trả lại bản sao bản sao chứ không phải bản gốc. –

+2

Bạn có thể trả về 'Arrays.asList (các ngày trong tuần)', sẽ không thay đổi. – Jivings

+2

@Jivings không đúng sự thật. Danh sách sẽ không chấp nhận các phần tử mới, nhưng phương thức set() hoạt động. –

Trả lời

3
private String[] weekdays =  
    {"Sun", "Mon", "Tue", "Thu", "Fri", "Sat", "Sun"}; 

public String[] getWeekdays() 
{  
    return weekdays; 
} 

Nếu bạn không sử dụng phương pháp clone, người dùng của lớp này có thể làm được rất nhiều điều phi đạo đức:

  1. thay đổi thứ tự của ngày,
  2. thay đổi tên của ngày,
  3. ...

Nhưng, trả lại bản sao sẽ không ảnh hưởng đến lớp và dữ liệu của nó. Vì vậy, những người dùng khác của lớp học sẽ không bị ảnh hưởng.

+0

Nhưng tôi đã không thấy rằng đề xuất phương pháp nhân bản() trên bất kỳ trang web nào trước đây. Tôi không thấy hầu hết các lập trình viên (thậm chí một số chuyên viên máy tính Java) sử dụng nó trong các ví dụ của họ. Tôi nghi ngờ, nếu đó là một thực hành mã hóa tốt thì sao? : O –

+0

@bomslang Rất nhiều thứ sẽ làm giảm yêu cầu của bạn. Như Azodious đã chỉ ra, không nhân bản (chứng minh bất kỳ bản sao dữ liệu nào khác) có thể dẫn đến các vấn đề bất ngờ cho lớp học của bạn, nhưng bạn cần quyết định xem đây có phải là hành vi mà bạn muốn hay không. Lý do bạn có thể không nhìn thấy nó là bởi vì nó gõ nhiều hơn cho hầu hết mọi người. Nếu bạn có một cái nhìn trong API Swing, bạn thấy rất nhiều thực hành mô phỏng, khi trả về 'Dimension', lớp sẽ thường tạo một đối tượng' Dimension' mới, sử dụng tham chiếu nội bộ của nó như là hạt giống của lớp mới, về cơ bản, nhân bản nó. – MadProgrammer

+2

Vâng, đúng thế. và cá nhân tôi đã sử dụng nó trong một trường hợp gần như tương tự như ví dụ của bạn. Nhưng nó không nên được sử dụng một cách mù quáng gây ra nếu một vật nặng được nhân bản, nó sẽ dẫn đến các vấn đề về bộ nhớ. Vì vậy, chỉ sao chép dữ liệu mà người dùng không sửa đổi. – Azodious

2

Bạn clone() or System.arraycopy() trên get() nếu bạn muốn đảm bảo rằng toàn bộ đồ thị đối tượng (có chứa mảng) là không thay đổi. Điều này được thực hiện thường khi API hiển thị mảng là công khai và có các ràng buộc về các giá trị trong mảng hoặc khi các đối tượng được truy cập bởi nhiều luồng. Trong những trường hợp như vậy, tính bất biến là quan trọng.

Giả sử bạn có đối tượng GroceryStore có phương thức getItemsSortedByPrice(). Bạn giữ các mục trong mảng duy trì thứ tự theo giá, nhưng nếu bạn trả về mảng này, mã máy khách có thể sửa đổi nó và phá vỡ các biến thể (nội bộ) của đối tượng của bạn.

Nếu đây là mã nội bộ (tức là) không phải là một phần của API công cộng, và bạn biết rằng bạn sẽ không sửa đổi mảng, sau đó nhân bản/đối phó có lẽ không cần thiết vì nó làm tổn thương hiệu suất mà không có lợi ích thực sự.

Tất cả phụ thuộc vào ngữ cảnh.

Mảng chỉ là các đối tượng và tất cả các quy tắc/thực hành biến đổi áp dụng cho một đối tượng thông thường, cũng áp dụng cho các mảng.

+1

+1 cho System.arrayCopy (), mặc dù tôi muốn giới thiệu phiên bản có thể sử dụng nhiều hơn Arrays.copyOf() (trong đó tất nhiên sử dụng System.arrayCopy() nội bộ) –

1

Tôi cho rằng hệ thống của bạn không khớp với mã Java được đề xuất. Ví dụ này là cho một usecase khác với của bạn.

Một mảng cuối cùng nghe có vẻ như tôi thích Enums và tôi nghĩ điều này phù hợp với yêu cầu của bạn tốt hơn nhiều.

5

Điều này được thảo luận trong cuốn sách "Java hiệu dụng" bởi Joshua Bloch. Có một phần được gọi là "Tạo bản sao phòng thủ khi cần" (Phần 39 trong ấn bản thứ hai).

Tôi nghĩ rằng sách của Google có thể cho phép bạn xem bản xem trước của phần.

Một cuốn sách hay để sống trên các chủ đề như thế này.

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