2011-07-16 36 views
22

Chỉ cần đọc trên trang web dev:Android Performance - 'Tránh nội Getters/setters'

Avoid Internal Getters/Setters

Trong các ngôn ngữ bản địa như C++ đó là thực tế phổ biến để sử dụng thu khí (ví dụ i = getCount()) thay vì truy cập trực tiếp vào trường (i = mCount). Đây là một thói quen tuyệt vời cho C++, vì trình biên dịch thường có thể truy cập nội tuyến và nếu bạn cần hạn chế hoặc gỡ lỗi truy cập trường, bạn có thể thêm mã bất kỳ lúc nào.

Trên Android, đây là một ý tưởng tồi. Các cuộc gọi phương thức ảo đắt tiền, nhiều hơn so với các lần tra cứu trường mẫu. Đó là hợp lý để làm theo thực hành lập trình hướng đối tượng phổ biến và có getters và setters trong giao diện công cộng, nhưng trong một lớp học, bạn nên luôn luôn truy cập trực tiếp các lĩnh vực.

Nếu không có JIT, truy cập trực tiếp trường nhanh hơn khoảng 3x so với gọi trình thu thập thông thường. Với JIT (nơi truy cập trực tiếp trường là rẻ như truy cập một địa phương), truy cập trực tiếp trường là khoảng 7x nhanh hơn so với gọi một getter tầm thường. Điều này đúng trong Froyo, nhưng sẽ cải thiện trong tương lai khi JIT vạch ra các phương pháp getter.

Vậy là nó nói rằng bạn sẽ sử dụng truy cập lĩnh vực trong phạm vi lớp:

public class MyObject { 

    public Object innerObject; // This would be private if I was using a getter 

    public void doSomeStuff(){ 
      if(innerObject){  // Within class access like this 
       // .... 
      } 
    } 

    public Object getInnerObject(){ // This would be removed if I was using field access 
     return innerObject; 
    } 
} 

Nhưng những gì về truy cập từ một đối tượng:

public class SecondObject { 

     public void doSecondSomething(){ 
       MyObject ob = new MyObject(); 
       Object inner; 

       //This is my question basically (from an Android performance perspective) 
       inner = ob.getInnerObject(); 
       // OR 
       inner = b.innerObject 

     } 

} 
+0

Để chỉ ra điều này, hãy nhớ rằng Dalvik không phải là JVM và thực hành này không nên được coi là một cách chung để làm trong phát triển Java bình thường. – Esko

+1

Trích dẫn của bạn nói tất cả, phải không? ** Đó là hợp lý để làm theo thực hành lập trình hướng đối tượng phổ biến và có getters và setters trong giao diện công cộng **. Ngoài ra: đừng đi quá mức thiết kế. Chỉ cần sử dụng getter trừ khi bạn thực hiện một số lượng lớn các cuộc gọi. hoặc có vấn đề về tốc độ. – Nanne

Trả lời

27

Các hit hiệu suất của việc sử dụng thu khí nội bộ và setters cũng áp dụng đối với thu khí bên ngoài và setters.

Tuy nhiên, trong trường hợp bên ngoài, getters và setters có lợi ích đáng kể ở các khu vực khác; ví dụ. bảo quản đóng gói, giảm khớp nối có hại, làm cho mã của bạn dễ bảo trì hơn, v.v. Vì vậy, nó thường được coi là thực hành tốt nhất để sử dụng getters và setters mặc dù hiệu suất hit mà điều này có thể phải chịu.

Lần truy cập hiệu suất là kết quả của các giới hạn của thế hệ hiện tại của trình biên dịch Android JIT cũ hơn. Tình huống này chắc chắn sẽ cải thiện đã được cải thiện với Gingerbread. (Tham khảo - https://stackoverflow.com/a/4930538/139985 ... và lưu ý ai đã viết câu trả lời đó!)

Nói chung, bạn nên "điều chỉnh" mã của bạn cho một nền tảng kém hơn, đặc biệt nếu có cơ hội hợp lý để có một nền tảng tốt hơn trong hoạt động offing.

+0

Đợi đã, JIT android không thực hiện các cuộc gọi chức năng tầm thường? Ý tôi là đó là một trong những tối ưu hóa cơ bản cho bất kỳ JIT nào - chắc chắn nó phải đảm bảo rằng lớp đó không bị ghi đè và cứ thế, nhưng điều đó dễ dàng ở mức 99/100. Khó tin. – Voo

+1

@Voo - Lý do kinh doanh có thể làm cho nó cần thiết để cung cấp một cái gì đó tỷ lệ thứ 2 bây giờ hơn chờ đợi 6 tháng cho đến khi nó là tỷ lệ 1. Điều tương tự cũng xảy ra với Java và Javascript (và Windows Vista, và ...). Nó chỉ là "khó tin" nếu bạn bỏ qua lịch sử. –

+0

Gửi nó! @StephenC tốt nhất cho bản cập nhật – Blundell

3
// this is faster 
inner = b.innerObject 

// but this won't hurt performance much because 
// it's assumed that it will be rare 
inner = ob.getInnerObject(); 
4

Mặc dù b.innerObject là nhanh hơn, như những tiến bộ công nghệ (cpus tốt hơn, JIT, vv) sự khác biệt giữa hai tùy chọn trở nên nhỏ hơn.

Điểm duy nhất mà nó có thể quan trọng là khi thực hiện trong vòng lặp chuyên sâu được thực hiện tất cả các thời gian. Ví dụ: trong phương thức onDraw của trò chơi, khi bạn lặp qua hàng trăm đối tượng.

3

Hãy nhớ rằng những cân nhắc hiệu suất đó chỉ có liên quan nếu thành viên được đề cập được truy cập hàng nghìn lần mỗi giây.

Một ví dụ tốt, nơi truy cập trực tiếp có thể là một ý tưởng tốt là scenegraph của một trò chơi (libgdx)

public abstract class Actor { 
    public Group parent; 
    public final String name; 
    public boolean touchable = true; 

    public float x; 
    public float y; 
    public float width; 
    public float height; 
    public float originX; 
    public float originY; 
    public float scaleX = 1; 
    public float scaleY = 1; 
    public float rotation; 
    public final Color color = new Color(1, 1, 1, 1); 
2

Getters and Setters luôn có phí ở trên vì chúng là các cuộc gọi chức năng. Khi bạn ở trong cùng một đối tượng, bạn có thể tối ưu hóa mã của mình bằng cách không sử dụng chúng như bạn biết chúng được sử dụng cho cái gì và bạn không cần phải tóm tắt/đóng gói chúng từ đối tượng riêng của nó.

Tôi nghĩ bạn cũng cần phải nhìn vào nó từ một góc độ khác nhau:

  1. một không có một getter/setter sẽ phá vỡ thông lệ oops chung? Bạn sẽ không muốn có tham chiếu trực tiếp nếu bạn đang tạo các đối tượng/mô-đun mà người khác sẽ sử dụng.

  2. Bạn thực sự không muốn sử dụng getters/setters quá nhiều lần như cuối cùng, trừ khi sh! * Tối ưu hóa của nó trong số các cuộc gọi chức năng sẽ có phí.

Bạn thực sự cần phải tối ưu hóa trên cơ sở percase, nếu tôi đang xây dựng hai mô-đun, nơi một số thành phần chỉ được truy cập bởi mỗi khác mà tôi có thể làm cho một lĩnh vực tĩnh khác tôi sẽ dính vào getters/setters

+1

"Getters and Setters luôn có phí trên vì chúng là các cuộc gọi hàm" không đúng trên bất kỳ JIT hiện đại nào - trong Hotspot sẽ được gạch chân, ngoại trừ một số trường hợp hiếm hoi (tức là setter thực sự bị ghi đè trong một subclass AND jit không thể đảm bảo một trong số nhận dạng của đối tượng - hoặc nói cách khác, hầu như không bao giờ) – Voo

2

Hiệu suất khôn ngoan, không có sự khác biệt trong việc truy cập this.field hoặc that.field.

Cảm giác rằng một trường thể hiện dễ tiếp cận hơn với đối tượng lưu trữ nó chỉ là ảo ảnh cú pháp.

OO, một cách khôn ngoan, ứng dụng Android có thể phức tạp đến mức nào? Nhiều người trong số các thần chú OO là từ việc xây dựng các ứng dụng quái vật. Thỏa thuận lớn nếu ứng dụng nhỏ của bạn sử dụng các đối tượng như cấu trúc là gì?

Và ngay cả trong một ứng dụng lớn, miễn là nó trong nhà, và tất cả các mã nguồn truy cập một trường có sẵn để tái cấu trúc, không có vấn đề gì ở tất cả các trường phơi bày.

0

Để ghi lại, một vấn đề khác với setter và getter (trong Java) là chúng rất khó sử dụng.

Hãy nói rằng các bài tập tiếp theo, chúng ta cần phải sửa đổi một người trong lĩnh vực một lĩnh vực của một đối tượng

Trong java là:

object.getField().getSubField().setField3("hello"); // ugly 

Trong khi trong C# cùng mã là (ngay cả với đóng gói)

object.Field.SubField.Field3="hello"; // fine 

Vì vậy, sử dụng lĩnh vực công cộng trong Java (hoặc android) là rất nhiều bụi:

object.field.subfield.field3="hello"; // fine too 
+1

nhưng đây là mẫu đối tượng TrainWreck, chỉ nói chuyện với người hàng xóm gần nhất và có mã 'object.setField3 (" hello ")); 'http://c2.com/cgi/wiki?TrainWreck – Blundell

+1

Tôi tìm thấy mô hình getter/setter là cách bán. 99% thời gian họ chỉ chuyển giao cho biến thành viên. Nếu bạn có kế hoạch thực hiện cả hai, chỉ cần bỏ qua getter/setter và biến biến thành public. Kỹ sư liên tục báo giá đóng gói tốt (hoặc cách ly cụ thể hơn) làm lợi ích chính cho bộ thu thập dữ liệu/setter. Mã được ràng buộc với cú pháp của getter/setter của bạn mà là giống hệt nhau để bị ràng buộc với biến thành viên lớp. Vì vậy, không đạt được. Việc đạt được là nếu bạn thay đổi thực hiện trong tương lai hoặc quá tải lớp dẫn xuất. Khi điều đó xảy ra, hãy làm cho getter/setter – user1959190

+0

@ user1959190 chính xác. Tuy nhiên, tôi không đồng ý với nhận xét về kỹ sư. Một kỹ sư thực sự tập trung vào hiệu quả và kết quả. Trong thực tế, một kỹ sư dày dạn cheats rất nhiều. Tuy nhiên, có rất nhiều lập trình viên không phải là kỹ sư nhưng gần gũi hơn với các nhà khoa học. Tôi sử dụng setter và getter vì nó là tiêu chuẩn và tinh thần đồng đội. Tuy nhiên, tôi cringe vì vô dụng của nó trong 99% thời gian, và khi nó hữu ích thì nó ẩn thực hiện và nó thực sự nguy hiểm. – magallanes