2012-10-05 19 views
5

Kịch bản là tôi cần truy cập một giá trị ít nhất hai lần. I E. Tôi đang sử dụng logger để theo dõi những gì đang xảy ra trong ứng dụng. Tôi muốn đăng nhập tên của đối tượng, chức năng đó đang hoạt động, và sau đó làm một cái gì đó với cùng một tên (ví dụ như kiểm tra nếu nó có chứa một số chuỗi hoặc đặt nó vào một mảng).Sử dụng các biến để lưu trữ các giá trị hoặc trực tiếp nhận các giá trị từ các đối tượng?

Lưu trữ các tên trong biến:

foo(Bar bar){ 
    String name = bar.getName(); 
    logger.info("I am working with "+name); 
    this.doSomethingWith(name); 
} 

Hoặc gọi getName() hai lần:

foo(Bar bar){ 
    logger.info("I am working with "+bar.getName()); 
    this.doSomethingWith(bar.getName()); 
} 

Tôi hiểu, rằng trong kịch bản đầu tiên, tôi sẽ tạo ra một chuỗi mới, gán một giá trị với nó và sau đó lấy giá trị này hai lần. Bằng cách này tôi đang sử dụng nhiều tài nguyên bộ nhớ hơn, đúng không?

Trong trường hợp thứ hai, tôi có đang truy cập thanh đối tượng hai lần và sau đó truy cập tên của nó hai lần. Tôi cho rằng đây không phải là phương pháp DRY. Nhưng mặt khác, tôi không lặp lại trong bộ nhớ, đúng không?

Phương pháp nào tốt hơn?

+0

Trong phương pháp đầu tiên bạn đang _không tạo chuỗi mới. Vì vậy, cả hai phương pháp nên kết thúc với mức tiêu thụ bộ nhớ tương tự. – Fildor

+0

Nó có thể là giá trị kiểm tra mã byte được tạo ra với một trình biên dịch ngược để xem vấn đề của bạn thực sự là một vấn đề; 'javac' có thể nhận ra trường hợp sử dụng này và tối ưu hóa nó theo cách này hay cách khác không có vấn đề gì theo cách bạn viết nó trong Java. – akaIDIOT

Trả lời

1

Cá nhân tôi thích phương pháp thứ hai. Thật vậy, tôi thường tạo biến tạm thời chỉ khi cần thiết.

Martin Fowler (http://en.wikipedia.org/wiki/Martin_Fowler) cũng tuân theo hướng dẫn này. Anh liên kết nó trong cuốn sách của ông mà tôi đã đọc:

http://www.amazon.fr/Refactoring-Improving-Design-Existing-Code/dp/0201485672

Một chiết xuất tự do của cuốn sách của mình liên quan đến chủ đề này là ở đây:

http://sourcemaking.com/refactoring/replace-temp-with-query

Một số người sẽ cho loại bỏ các biến tạm thời có thể dẫn đến vấn đề hiệu suất.

Như Martin Fowler nói:

Bạn có thể lo ngại về hiệu suất trong trường hợp này. Như với các vấn đề về hiệu suất khác, hãy để nó trượt ngay bây giờ. Chín lần trong số mười, điều đó sẽ không thành vấn đề. Khi có vấn đề, bạn sẽ khắc phục sự cố trong quá trình tối ưu hóa.Với mã của bạn tốt hơn yếu tố, bạn sẽ thường xuyên tìm tối ưu hóa mạnh mẽ hơn, mà bạn có thể đã bỏ lỡ mà không cần tái cấu trúc. Nếu tình trạng tồi tệ trở nên tồi tệ hơn, rất dễ dàng để đặt temp trở lại.

Nhưng dù sao, đó là vấn đề về hương vị. Một số người thấy dễ tiếp cận hơn cách tiếp cận đầu tiên, những người khác là thứ hai. Tôi thực sự thích thứ hai vì tôi ghét các biến tạm thời thêm các dòng không có giá trị thực :)

+0

Cách tiếp cận Martin Fowler này ... TUYỆT VỜI! – user1581900

+0

@ user1581900 Bạn nên đọc cuốn sách của mình, tôi thích nó :) Xem thêm Robert C Martin cho cuốn sách "Clean Code" :) – Mik378

1

Bar Lớp không thay đổi (đối với hầu hết các trường hợp). Đối với lớp bất biến, các phương pháp này đều giống nhau, vì vậy bạn chọn bất cứ thứ gì bạn thích.

Bất kỳ vấn đề thực sự nào cũng sẽ chỉ xảy ra nếu Bar có thể thay đổi, do đó giá trị bar.name có thể thay đổi giữa 2 lần đọc. Nhưng trường hợp này sẽ kết xuất bằng cách sử dụng Bar làm đối tượng miền (mà nó dường như là) vô nghĩa. Bạn có thể làm việc xung quanh các trường hợp như vậy bằng cách tạo bản sao cục bộ của bar ở đầu foo(). Sau đó, một lần nữa, một khi bạn có bản sao địa phương của bản gốc bar, bạn có thể chọn bất cứ cách nào bạn thích hơn.

Vì vậy, đây là vấn đề về hương vị. Có, bạn có thể phí một chút bộ nhớ để tham chiếu cục bộ trong trường hợp đầu tiên, nhưng có lẽ nhất, JVM sẽ tối ưu hóa nó đi để làm cho nó trông giống như cách thứ 2 trên cấp byte-mã.

3

Bạn không sử dụng nhiều bộ nhớ hơn trong ví dụ đầu tiên, vì String là một đối tượng không thay đổi. Như vậy, bất kỳ tham chiếu đến một String chỉ đơn giản là một con trỏ đến cùng một đối tượng trong bộ nhớ.

Tùy chọn thứ hai cũng có một số vấn đề về an toàn luồng khi kết quả của getName() có thể thay đổi giữa các lời gọi. Mặc dù có thể không chắc, đó là điều bạn có thể muốn cân nhắc.

Với ý nghĩ đó, tôi sẽ khuyên bạn nên sử dụng tùy chọn đầu tiên mặc dù nó có nhiều tính năng "nói nhiều" hơn.

Lưu ý: Cũng có thể là getName() được tạo bằng tính toán, trong trường hợp này bạn sẽ thực sự kết thúc bằng phương pháp thứ hai sử dụng nhiều bộ nhớ hơn bộ nhớ đầu tiên.

+0

Vì vậy, trong kịch bản đầu tiên cả hai String name và bar.getName() trỏ đến cùng một String trong bộ nhớ. Nếu tôi thay đổi bar.name Tôi không thực sự thay đổi nó, nhưng chỉ nó vào một số String khác, trong khi String name vẫn sẽ trỏ đến giá trị cũ? – user1581900

+1

Điều đó là chính xác. Đây là lý do tại sao tất cả các phương thức trong java.lang.String trả về một String mới thay vì sửa đổi đối tượng mà chúng đang được gọi. –

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