Bài viết này hướng đến những người lần đầu tiên biết đến khái niệm hoa văn, đã nghe nói về
Singleton
e hoặc bằng cách nào đó đã làm ra nó nhưng vẫn chưa hiểu gì cả. Chào mừng! Học sinh JavaRush lần đầu tiên gặp các mẫu ở cấp 15, khi bất ngờ, giới hạn yêu cầu “sửa” và triển khai một mẫu
Singleton
với cách triển khai lười biếng. Những học sinh lần đầu tiên nghe về nó
Singleton
sẽ ngay lập tức đặt ra một loạt câu hỏi: mẫu là gì, tại sao nó lại cần thiết, loại mẫu đó là gì
Singleton
và cuối cùng, đây là kiểu triển khai lười biếng như thế nào. Hãy bắt đầu trả lời theo thứ tự:
Dù sao thì mô hình là gì?
Để hiểu rõ hơn, tôi nghĩ đáng để trả lời câu hỏi này từ lịch sử. Trong số các lập trình viên có bốn tác giả nổi tiếng: Erich Gamma, Richard Helm, Ralph Johnson và John Vlissides, người đã nghĩ ra một ý tưởng thú vị.
Họ nhận thấy rằng khi viết chương trình, họ thường phải giải những bài toán gần giống nhau và viết mã cùng loại về cấu trúc. Vì vậy, họ quyết định mô tả dưới dạng các mẫu hình điển hình thường được sử dụng trong lập trình hướng đối tượng. Cuốn sách được xuất bản năm 1995 với tựa đề
“Kỹ thuật thiết kế hướng đối tượng”. Mẫu thiết kế" . Tiêu đề của cuốn sách hóa ra quá dài và nó được biết đến đơn giản với
cái tên Cuốn sách của bốn tên tội phạm . Trong ấn bản đầu tiên, 23 mẫu đã được xuất bản, sau đó hàng chục mẫu khác đã được phát hiện. Vì vậy, để trả lời câu hỏi trong đoạn này,
“Mẫu là gì?” , hãy tóm tắt chỉ trong vài từ:
Mẫu là một giải pháp được tiêu chuẩn hóa cho một vấn đề chung. |
Và
Singleton
đây chỉ là một trong những mẫu này.
Tại sao chúng ta cần mẫu (mẫu thiết kế)
Bạn có thể lập trình mà không cần biết các mẫu; bạn có thể xác minh điều này một cách đơn giản bằng cách nhận ra thực tế là ở cấp độ 15 trong JavaRush, bạn đã viết hàng trăm chương trình nhỏ mà không biết gì về sự tồn tại của chúng. Điều này cho thấy rằng mẫu là một loại công cụ, sự hiện diện của nó giúp phân biệt một bậc thầy với một người nghiệp dư:
Các mẫu mô tả cách giải quyết chính xác một trong những vấn đề điển hình. Kết quả là, biết các mẫu giúp bạn tiết kiệm thời gian. Một sự tương tự có thể được thực hiện với các thuật toán. Ví dụ: bạn có thể nghĩ ra thuật toán sắp xếp của riêng mình
với blackjack và các con số và dành nhiều thời gian cho nó hoặc bạn có thể sử dụng một thuật toán đã được mô tả từ lâu và triển khai nó. Điều này cũng tương tự với các mẫu. Ngoài ra, với việc sử dụng các mẫu, mã sẽ trở nên chuẩn hóa hơn và khi sử dụng đúng mẫu, bạn sẽ ít mắc lỗi hơn vì chúng đã được đoán trước và loại bỏ trong mẫu này. Ngoài ra, kiến thức về các mẫu cho phép các lập trình viên hiểu nhau hơn. Chỉ cần nói tên của mẫu là đủ, thay vì cố gắng giải thích cho các lập trình viên đồng nghiệp của bạn những gì bạn muốn họ làm.
Vì vậy, tóm lại, các mẫu thiết kế giúp:
- không phát minh lại bánh xe mà sử dụng các giải pháp tiêu chuẩn;
- chuẩn hóa mã;
- chuẩn hóa thuật ngữ;
|
Để kết luận phần này, chúng tôi lưu ý rằng toàn bộ các mẫu có thể được đơn giản hóa thành ba nhóm lớn:
Cuối cùng là mẫu Singleton
Singleton
đề cập đến
các mô hình sáng tạo . Bản dịch theo nghĩa đen của nó là cô đơn. Mẫu này đảm bảo rằng một lớp chỉ có một đối tượng (một phiên bản của lớp) và một điểm truy cập toàn cầu được cung cấp cho đối tượng đó. Cần phải rõ ràng từ mô tả rằng mẫu này nên được sử dụng trong hai trường hợp:
- khi không nên tạo nhiều hơn một đối tượng của bất kỳ lớp nào trong chương trình của bạn. Ví dụ: trong trò chơi máy tính, bạn có lớp “Nhân vật” và lớp này chỉ được có một đối tượng mô tả chính nhân vật đó.
- khi bạn cần cung cấp điểm truy cập toàn cầu cho một đối tượng lớp. Nói cách khác, bạn cần đảm bảo rằng đối tượng được gọi từ bất kỳ đâu trong chương trình. Và, than ôi, đối với điều này, chỉ tạo một biến toàn cục là chưa đủ, bởi vì nó không được bảo vệ chống ghi và bất kỳ ai cũng có thể thay đổi giá trị của biến này và điểm truy cập toàn cục vào đối tượng sẽ bị mất. Các thuộc tính này
Singleton
cần thiết, chẳng hạn như khi bạn có một đối tượng của một lớp làm việc với cơ sở dữ liệu và bạn cần có thể truy cập được cơ sở dữ liệu đó từ các phần khác nhau của chương trình. Và Singleton
nó sẽ đảm bảo rằng không có mã nào khác thay thế thể hiện của lớp được tạo trước đó.
Hai vấn đề này được giải quyết bằng cách
Singleton
: chỉ có một đối tượng trong chương trình và phải có quyền truy cập toàn cục vào nó. Trong ví dụ ở cấp 15, giới hạn yêu cầu triển khai mẫu này cho nhiệm vụ sau (đây là mô tả của nó):
Sau khi đọc kỹ điều kiện, bạn sẽ hiểu rõ tại sao chính xác
Singleton
(Đơn) lại cần thiết ở đây. Cuối cùng, chương trình yêu cầu bạn tạo một đối tượng cho mỗi lớp:
Sun
,
Moon
,
Earth
. Và thật hợp lý khi giả định rằng mỗi lớp trong chương trình không nên tạo nhiều hơn một Mặt trời/Mặt trăng/Trái đất, nếu không sẽ là vô lý, trừ khi tất nhiên bạn đang viết phiên bản Chiến tranh giữa các vì sao của riêng mình.
Tính năng triển khai Singleton
Java theo ba bước Không thể triển khai hành vi Singleton trong Java bằng cách sử dụng một hàm tạo thông thường vì hàm tạo đó luôn trả về một đối tượng mới. Do đó, tất cả việc triển khai
Singleton
'a đều đi đến việc ẩn hàm tạo và tạo một phương thức tĩnh công khai sẽ kiểm soát sự tồn tại của một đối tượng duy nhất và "hủy" tất cả các đối tượng mới xuất hiện. Nếu
Singleton
'a được gọi, nó phải tạo một đối tượng mới (nếu nó chưa có trong chương trình) hoặc trả về một đối tượng đã được tạo. Để làm điều này:
#1. – Bạn cần thêm một trường tĩnh riêng vào lớp chứa một đối tượng:
public class LazyInitializedSingleton {
private static LazyInitializedSingleton instance;
}
#2. – Đặt hàm tạo của lớp (hàm tạo mặc định) ở chế độ riêng tư (để quyền truy cập vào nó bị đóng bên ngoài lớp, khi đó nó sẽ không thể trả về các đối tượng mới):
public class LazyInitializedSingleton {
private static LazyInitializedSingleton instance;
private LazyInitializedSingleton(){}
}
#3 . – Khai báo một phương thức tạo tĩnh sẽ được sử dụng để lấy singleton:
public class LazyInitializedSingleton {
private static LazyInitializedSingleton instance;
private LazyInitializedSingleton(){}
public static LazyInitializedSingleton getInstance(){
if(instance == null){
instance = new LazyInitializedSingleton();
}
return instance;
}
}
Ví dụ trên hơi vụng về, vì chúng ta chỉ đơn giản ẩn hàm tạo và cung cấp phương thức của riêng mình thay vì hàm tạo tiêu chuẩn. Vì bài viết này nhằm mục đích giúp sinh viên JavaRush tiếp xúc với mẫu này (và các mẫu nói chung) lần đầu tiên nên các tính năng triển khai của Singletons phức tạp hơn sẽ không được đưa ra ở đây. Chúng tôi chỉ lưu ý rằng tùy thuộc vào độ phức tạp của chương trình, có thể cần phải sàng lọc chi tiết hơn mẫu này. Ví dụ: trong môi trường đa luồng (xem chủ đề Luồng), một số luồng khác nhau có thể đồng thời gọi phương thức getter của Singleton và mã được mô tả ở trên sẽ ngừng hoạt động, vì mỗi luồng riêng lẻ sẽ có thể tạo nhiều phiên bản của lớp một lần. Do đó, vẫn có một số cách tiếp cận khác nhau để tạo ra các singleton an toàn cho Thread. Nhưng đó lại là một câu chuyện khác =))
Và cuối cùng. Khởi tạo lười biếng mà giới hạn yêu cầu là gì ?Khởi tạo lười biếng còn được gọi là khởi tạo lười biếng. Đây là một kỹ thuật lập trình trong đó một hoạt động sử dụng nhiều tài nguyên (và việc tạo một đối tượng là một hoạt động sử dụng nhiều tài nguyên) được thực hiện theo yêu cầu, thay vì thực hiện trước. Về cơ bản đó là những gì xảy ra trong mã của chúng tôi
Singleton
'a. Nói cách khác, đối tượng của chúng tôi được tạo tại thời điểm nó được truy cập chứ không phải trước đó. Không nên cho rằng khái niệm khởi tạo lười biếng bằng cách nào đó có mối liên hệ chặt chẽ với
Singleton
'om. Khởi tạo lười biếng cũng được sử dụng trong các mẫu thiết kế tổng quát khác, ví dụ như trong Proxy và Factory Method, nhưng đó lại là một câu chuyện khác =)
Các nguồn sau đây đã được sử dụng để chuẩn bị cho bài viết:
- Mẫu thiết kế Java Singleton Thực tiễn tốt nhất kèm theo ví dụ
- Mẫu thiết kế
- Singleton đúng trong Java
GO TO FULL VERSION