CodeGym /Blog Java /Ngẫu nhiên /Mẫu và Singleton trong Java

Mẫu và Singleton trong Java

Xuất bản trong nhóm
Bài viết này dành cho bất kỳ ai lần đầu tiên bắt gặp khái niệm về mẫu thiết kế, đã nghe thấy thuật ngữ singleton hoặc bằng cách nào đó đã triển khai mẫu đơn nhưng không hiểu chuyện gì đang xảy ra. Chào mừng! Các sinh viên CodeGym bắt gặp các mẫu thiết kế lần đầu tiên ở Cấp độ 15, khi đội trưởng bất ngờ yêu cầu họ "củng cố" hiểu biết của mình bằng cách triển khai mẫu Java Singleton với việc triển khai lười biếng. Sinh viên lần đầu tiên nghe về mẫu đơn lập tức có rất nhiều câu hỏi: mẫu thiết kế là gì trên thế giới? Tại sao chúng ta cần nó? Độc thân là gì ? Và cuối cùng, triển khai lười biếng là gì? Hãy trả lời những câu hỏi này theo thứ tự.

Những gì trên thế giới là một mẫu thiết kế?

Tôi tin rằng một chút lịch sử là để trả lời câu hỏi này với sự hiểu biết tốt nhất. Có bốn tác giả lập trình nổi tiếng (Erich Gamma, John Vlissides, Ralph Johnson và Richard Helm) đã đưa ra một ý tưởng thú vị. Họ nhận thấy rằng việc phát triển phần mềm thường yêu cầu họ giải quyết các vấn đề gần giống nhau và viết mã có cấu trúc theo cùng một cách. Vì vậy, họ quyết định mô tả các mẫu điển hình thường cần được sử dụng trong lập trình hướng đối tượng. Cuốn sách của họ được xuất bản năm 1994 với tựa đề Design Patterns: Elements of Reusable Object-Oriented Software. Tên của cuốn sách hóa ra quá dài và mọi người bắt đầu gọi nó đơn giản là cuốn sách của Gang of Four. Phiên bản đầu tiên bao gồm 23 mẫu. Sau đó, hàng chục mẫu khác đã được phát hiện.
Một mẫu thiết kế là một giải pháp tiêu chuẩn hóa cho một vấn đề chung.
Và mô hình singleton chỉ là một trong số đó.

Tại sao chúng ta cần các mẫu thiết kế?

Bạn có thể lập trình mà không cần biết các mẫu: xét cho cùng, ở Cấp độ 15, bạn đã viết hàng trăm chương trình nhỏ trên CodeGym mà không hề biết rằng chúng tồn tại. Điều này gợi ý rằng các mẫu thiết kế là một loại công cụ mà cách sử dụng của nó phân biệt giữa bậc thầy với người nghiệp dư: Các mẫu thiết kế mô tả cách giải quyết đúng đắn một vấn đề điển hình. Điều này có nghĩa là biết các mẫu giúp bạn tiết kiệm thời gian. Theo cách đó, chúng tương tự như các thuật toán. Ví dụ: bạn có thể tạo thuật toán sắp xếp của riêng mình với blackjack và sốvà dành nhiều thời gian để làm như vậy, hoặc bạn có thể thực hiện một điều đã được hiểu và mô tả trong một thời gian dài. Điều này cũng đúng với các mẫu thiết kế. Ngoài ra, với các mẫu thiết kế, mã trở nên tiêu chuẩn hơn và khi sử dụng mẫu phù hợp, bạn sẽ ít mắc lỗi hơn vì các cạm bẫy phổ biến của mẫu đã được xác định và loại bỏ từ lâu. Trên hết, kiến ​​thức về các mẫu giúp các lập trình viên hiểu nhau hơn. Bạn có thể chỉ cần nói tên của một mẫu thay vì cố gắng giải thích dài dòng cho các lập trình viên đồng nghiệp của mình. Tóm lại, các mẫu thiết kế giúp bạn:
  • không phát minh lại bánh xe, mà thay vào đó 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 thúc phần này, chúng tôi lưu ý rằng toàn bộ các mẫu thiết kế có thể được chia thành ba nhóm lớn: Patterns và singleton - dành cho ai lần đầu gặp - 2

Cuối cùng, mẫu singleton

Singleton là một mô hình sáng tạo . Mẫu này đảm bảo rằng chỉ có một thể hiện của một lớp và cung cấp một điểm truy cập toàn cục cho đối tượng này. Từ mô tả, rõ ràng là mẫu này nên được áp dụng trong hai trường hợp:
  1. khi chương trình của bạn yêu cầu không tạo nhiều hơn một đối tượng của một lớp cụ thể. Ví dụ: trò chơi trên máy tính có thể có lớp Anh hùng và chỉ một đối tượng Anh hùng mô tả anh hùng duy nhất trong trò chơi.

  2. khi bạn cần cung cấp một điểm để truy cập toàn cục vào một đối tượng. Nói cách khác, bạn cần làm cho đối tượng có sẵn từ bất kỳ đâu trong chương trình. Than ôi, chỉ tạo một biến toàn cục là không đủ, vì nó không được bảo vệ chống ghi: bất kỳ ai cũng có thể thay đổi giá trị của biến, do đó, điểm truy cập toàn cầu của đối tượng có thể bị mất. Ví dụ, các thuộc tính này của Singleton là cần thiết khi bạn có một đối tượng hoạt động với cơ sở dữ liệu và bạn cần truy cập cơ sở dữ liệu từ các phần khác nhau của chương trình. Một Singleton sẽ đảm bảo rằng không ai viết mã thay thế phiên bản đã tạo trước đó.
Vì vậy, một Singleton thỏa mãn hai nhu cầu này: chỉ phải có một loại đối tượng nhất định trong chương trình và phải có quyền truy cập toàn cầu vào đối tượng đó. Trong ví dụ ở Cấp độ 15, đội trưởng yêu cầu bạn thực hiện mẫu này cho nhiệm vụ sau:
  1. Tìm một ví dụ về Singleton với khởi tạo lười biếng.

  2. Tạo ba lớp đơn lẻ - Mặt trời, Mặt trăng, Trái đất - trong các tệp riêng biệt bằng cách sử dụng cùng một nguyên tắc.

  3. Thực hiệnHành tinhgiao diện trong các lớp Sun , MoonEarth .

  4. Trong khối tĩnh của lớp Giải pháp , hãy gọireadKeyFromConsoleAndInitPlanetphương pháp.

  5. Thực hiện cácreadKeyFromConsoleAndInitPlanetChức năng phương pháp:

    • 5.1. Đọc một tham số Chuỗi từ bảng điều khiển

    • 5.2. Nếu tham số bằng một trong cácHành tinhhằng số của giao diện, hãy tạo đối tượng thePlanet phù hợp .

Sau khi đọc kỹ các điều kiện của nhiệm vụ, chúng ta có thể thấy rõ tại sao lại cần một Singleton ở đây. Thật vậy, chúng ta được yêu cầu tạo một thể hiện của từng lớp sau: Sun , Moon , Earth . Thật hợp lý khi cho rằng chúng ta không nên tạo ra nhiều hơn một Mặt trời/Mặt trăng/Trái đất. Mặt khác, chúng ta rơi vào một tình huống vô lý, tất nhiên là trừ khi bạn đang viết phiên bản Chiến tranh giữa các vì sao của mình. Triển khai mẫu Singleton trong Java theo ba bước Trong Java, hành vi Singleton không thể được triển khai bằng cách sử dụng 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ả các triển khai của Singletonchuyển sang ẩn hàm tạo, tạo một phương thức tĩnh công khai kiểm soát thời gian tồn tại của đối tượng đơn lẻ và "hủy" tất cả các đối tượng mới xuất hiện. Nếu một Singleton được truy cập, nó sẽ tạo một đối tượng mới (nếu một đối tượng chưa tồn tại trong chương trình) hoặc trả về một đối tượng hiện có. Để hoàn thành việc này:
  1. Bạn cần cung cấp cho lớp một trường tĩnh riêng lưu trữ một đối tượng:

    
    public class LazyInitializedSingleton {
    	private static LazyInitializedSingleton instance; // #1
    }
    
  2. Đặt hàm tạo (mặc định) ở chế độ riêng tư. Điều này có nghĩa là nó không thể được truy cập bên ngoài lớp và sẽ không thể trả về các đối tượng mới:

    
    public class LazyInitializedSingleton {
    	private static LazyInitializedSingleton instance;
    private LazyInitializedSingleton(){} // #2
    } 
    
  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() { // #3
            if (instance == null) { // If the object has not yet been created
                instance = new LazyInitializedSingleton(); // Create a new object
            }
            return instance; // Return the previously created object
        }
    }
    
Ví dụ trên hơi vụng về, vì chúng ta chỉ cần ẩn hàm tạo và cung cấp phương thức của riêng chúng ta thay vì một hàm tạo tiêu chuẩn. Vì bài viết này nhằm mục đích đảm bảo rằng sinh viên CodeGym tiếp xúc với mẫu này (và các mẫu thiết kế nói chung), các sắc thái của việc triển khai đơn lẻ phức tạp hơn sẽ không được mô tả ở đâ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, mẫu này có thể cần được tinh chỉnh thêm. Ví dụ: trong môi trường đa luồng (xem các bài viết về luồng), một số luồng khác nhau có thể truy cập đồng thời phương thức singleton và mã được mô tả ở trên sẽ ngừng hoạt động vì mỗi luồng riêng biệt có thể tạo một thể hiện của lớp. Do đó, vẫn còn một số cách tiếp cận khác nhau để tạo các singletons an toàn cho luồng phù hợp. 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 này là gì mà đội trưởng hỏi về?

Khởi tạo chậm còn được gọi là khởi tạo chậm. Đây là thủ thuật lập trình trong đó thao tác sử dụng nhiều tài nguyên (và tạo đối tượng là thao tác sử dụng nhiều tài nguyên) được thực hiện theo yêu cầu thay vì trước. Vậy điều gì thực sự xảy ra trong mã Java Singleton của chúng ta ? Nói cách khác, đối tượng của chúng ta được tạo vào thời điểm nó được truy cập, không phải trước. Bạn không nên cho rằng việc khởi tạo lười biếng bằng cách nào đó bị ràng buộc chặt chẽ với mẫu Singleton . Khởi tạo lười biếng cũng được sử dụng trong các mẫu thiết kế sáng tạo khác, chẳng hạn như Proxy và Factory Method, nhưng đây cũng là một câu chuyện khác =)
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION