Nếu bạn đang sử dụng từ khóa 'tĩnh' mà không có từ khóa 'cuối cùng', đây sẽ là một tín hiệu để xem xét cẩn thận thiết kế của bạn. Ngay cả sự hiện diện của 'trận chung kết' cũng không phải là đường chuyền miễn phí, vì một đối tượng tĩnh cuối có thể thay đổi có thể nguy hiểm như vậy.
Tôi sẽ ước tính ở đâu đó khoảng 85% thời gian tôi thấy một "tĩnh" mà không có "trận chung kết", đó là SAI. Thông thường, tôi sẽ tìm cách giải quyết lạ để che giấu hoặc che giấu những vấn đề này.
Vui lòng không tạo đột biến tĩnh. Đặc biệt là Bộ sưu tập. Nói chung, Bộ sưu tập nên được khởi tạo khi đối tượng chứa của chúng được khởi tạo và nên được thiết kế sao cho chúng được đặt lại hoặc quên khi đối tượng chứa của chúng bị lãng quên.
Sử dụng statics có thể tạo ra những lỗi rất tinh vi sẽ gây ra những ngày đau khổ cho các kỹ sư. Tôi biết, bởi vì tôi đã tạo và săn những con bọ này.
Nếu bạn muốn biết thêm chi tiết, vui lòng đọc trên giáo dục
Tại sao không sử dụng Statics?
Có nhiều vấn đề với thống kê, bao gồm viết và thực hiện các bài kiểm tra, cũng như các lỗi tinh vi không rõ ràng ngay lập tức.
Mã dựa trên các đối tượng tĩnh không thể dễ dàng được kiểm tra đơn vị và các thống kê không thể dễ dàng bị chế giễu (thông thường).
Nếu bạn sử dụng statics, không thể hoán đổi việc thực hiện lớp để kiểm tra các thành phần cấp cao hơn. Ví dụ, hãy tưởng tượng một CustomerDAO tĩnh trả về các đối tượng Khách hàng mà nó tải từ cơ sở dữ liệu. Bây giờ tôi có một lớp Trình khách hàng, cần truy cập vào một số đối tượng Khách hàng. Nếu CustomerDAO là tĩnh, tôi không thể viết bài kiểm tra cho Bộ lọc khách hàng mà không khởi tạo cơ sở dữ liệu của mình trước đó và điền thông tin hữu ích.
Và cơ sở dữ liệu dân số và khởi tạo mất một thời gian dài. Và theo kinh nghiệm của tôi, khung khởi tạo DB của bạn sẽ thay đổi theo thời gian, có nghĩa là dữ liệu sẽ biến đổi và các thử nghiệm có thể bị hỏng. IE, hãy tưởng tượng Khách hàng 1 từng là VIP, nhưng khung khởi tạo DB đã thay đổi và bây giờ Khách hàng 1 không còn là VIP, nhưng thử nghiệm của bạn đã được mã hóa cứng để tải Khách hàng 1
Một cách tiếp cận tốt hơn là khởi tạo một CustomerDAO và chuyển nó vào Bộ lọc khách hàng khi nó được xây dựng. (Một cách tiếp cận thậm chí tốt hơn sẽ là sử dụng Spring hoặc khung Inversion of Control khác.
Khi bạn thực hiện việc này, bạn có thể nhanh chóng mô phỏng hoặc loại bỏ một DAO thay thế trong CustomerFilterTest của bạn, cho phép bạn có nhiều quyền kiểm soát hơn đối với bài kiểm tra,
Nếu không có DAO tĩnh, thử nghiệm sẽ nhanh hơn (không khởi tạo db) và đáng tin cậy hơn (vì sẽ không thất bại khi mã khởi tạo db thay đổi). Ví dụ: trong trường hợp này, đảm bảo Khách hàng 1 luôn luôn là VIP, theo như thử nghiệm có liên quan.
Kiểm tra thực hiện
Số liệu thống kê gây ra sự cố thực sự khi chạy các bộ kiểm tra đơn vị cùng nhau (ví dụ: với máy chủ Tích hợp liên tục của bạn). Tưởng tượng một bản đồ tĩnh của các đối tượng Ổ cắm mạng vẫn mở từ thử nghiệm này sang thử nghiệm khác. Thử nghiệm đầu tiên có thể mở một Ổ cắm trên cổng 8080, nhưng bạn đã quên xóa Bản đồ khi thử nghiệm bị phá hỏng. Bây giờ khi thử nghiệm thứ hai khởi chạy, nó có khả năng bị sập khi cố gắng tạo một Ổ cắm mới cho cổng 8080, do cổng vẫn bị chiếm dụng. Cũng hãy tưởng tượng rằng các tham chiếu socket trong Bộ sưu tập tĩnh của bạn không bị xóa và (ngoại trừ WeakHashMap) không bao giờ đủ điều kiện để được thu gom rác, gây rò rỉ bộ nhớ.
Đây là một ví dụ khái quát quá mức, nhưng trong các hệ thống lớn, vấn đề này xảy ra TẤT CẢ THỜI GIAN. Mọi người không nghĩ về các thử nghiệm đơn vị bắt đầu và dừng phần mềm của họ liên tục trong cùng một JVM, nhưng đó là một thử nghiệm tốt về thiết kế phần mềm của bạn và nếu bạn có nguyện vọng về tính sẵn sàng cao, đó là điều bạn cần lưu ý.
Những vấn đề này thường phát sinh với các đối tượng khung, ví dụ: quyền truy cập DB, bộ nhớ đệm, nhắn tin và các lớp ghi nhật ký của bạn. Nếu bạn đang sử dụng Java EE hoặc một số khung công tác tốt nhất, họ có thể quản lý rất nhiều điều này cho bạn, nhưng nếu như tôi, bạn đang xử lý một hệ thống cũ, bạn có thể có rất nhiều khung tùy chỉnh để truy cập các lớp này.
Nếu cấu hình hệ thống áp dụng cho các thành phần khung này thay đổi giữa các thử nghiệm đơn vị và khung thử nghiệm đơn vị không phá hủy và xây dựng lại các thành phần, các thay đổi này không thể có hiệu lực và khi thử nghiệm dựa vào các thay đổi đó, chúng sẽ thất bại .
Ngay cả các thành phần phi khung cũng phải chịu vấn đề này. Hãy tưởng tượng một bản đồ tĩnh được gọi là OpenOrder. Bạn viết một bài kiểm tra tạo ra một vài đơn đặt hàng mở và kiểm tra để đảm bảo tất cả chúng đều ở trạng thái phù hợp, sau đó bài kiểm tra kết thúc. Một nhà phát triển khác viết một bài kiểm tra thứ hai trong đó đặt các đơn đặt hàng mà họ cần vào bản đồ OpenOrder, sau đó xác nhận số lượng đơn đặt hàng là chính xác. Chạy riêng lẻ, các bài kiểm tra này sẽ vượt qua, nhưng khi chạy cùng nhau trong một bộ, chúng sẽ thất bại.
Tệ hơn, thất bại có thể dựa trên thứ tự các bài kiểm tra đã được chạy.
Trong trường hợp này, bằng cách tránh các số liệu thống kê, bạn tránh được rủi ro lưu giữ dữ liệu trong các trường hợp kiểm tra, đảm bảo độ tin cậy kiểm tra tốt hơn.
Lỗi tinh tế
Nếu bạn làm việc trong môi trường có tính sẵn sàng cao hoặc bất cứ nơi nào có thể bắt đầu và dừng các luồng, thì mối quan tâm tương tự được đề cập ở trên với các bộ kiểm thử đơn vị cũng có thể áp dụng khi mã của bạn đang chạy trên sản xuất.
Khi xử lý các luồng, thay vì sử dụng một đối tượng tĩnh để lưu trữ dữ liệu, tốt hơn là sử dụng một đối tượng được khởi tạo trong giai đoạn khởi động của luồng. Theo cách này, mỗi khi luồng được khởi động, một phiên bản mới của đối tượng (với cấu hình có khả năng mới) được tạo và bạn tránh dữ liệu từ một phiên bản của luồng chảy qua phiên bản tiếp theo.
Khi một luồng chết, một đối tượng tĩnh không được thiết lập lại hoặc rác được thu thập. Hãy tưởng tượng bạn có một chuỗi có tên là Email EmailCustomers 'và khi nó bắt đầu, nó sẽ tạo ra một bộ sưu tập Chuỗi tĩnh với một danh sách các địa chỉ email, sau đó bắt đầu gửi email cho từng địa chỉ. Hãy nói rằng luồng bị gián đoạn hoặc bị hủy bằng cách nào đó, vì vậy khung sẵn sàng cao của bạn khởi động lại luồng. Sau đó, khi chủ đề khởi động, nó tải lại danh sách khách hàng. Nhưng vì bộ sưu tập là tĩnh, nên nó có thể giữ lại danh sách các địa chỉ email từ bộ sưu tập trước đó. Bây giờ một số khách hàng có thể nhận được email trùng lặp.
Bên cạnh: Chung kết tĩnh
Việc sử dụng của static static cuối cùng là một cách hiệu quả tương đương với Java của C #define, mặc dù có những khác biệt về triển khai kỹ thuật. Bộ xử lý trước AC / C ++ #define bị tráo đổi mã trước khi biên dịch. Một bản cuối cùng của Java Java sẽ kết thúc cư dân bộ nhớ trên ngăn xếp. Theo cách đó, nó tương tự như một biến const const tĩnh trong C ++ so với biến #define.
Tóm lược
Tôi hy vọng điều này sẽ giúp giải thích một vài lý do cơ bản tại sao số liệu thống kê có vấn đề. Nếu bạn đang sử dụng một khung công tác Java hiện đại như Java EE hoặc Spring, v.v., bạn có thể không gặp phải nhiều tình huống này, nhưng nếu bạn đang làm việc với một khối mã kế thừa lớn, chúng có thể trở nên thường xuyên hơn.