Điều quan trọng là phải phân biệt ở đây giữa các trường hợp đơn và mẫu thiết kế Singleton .
Các trường hợp đơn giản chỉ là một thực tế. Hầu hết các ứng dụng chỉ được thiết kế để hoạt động với một cấu hình tại một thời điểm, một giao diện người dùng tại một thời điểm, một hệ thống tệp tại một thời điểm, v.v. Nếu có rất nhiều trạng thái hoặc dữ liệu được duy trì, thì chắc chắn bạn sẽ muốn chỉ có một phiên bản và giữ cho nó tồn tại càng lâu càng tốt.
Mẫu thiết kế Singleton là một loại ví dụ rất cụ thể , cụ thể là:
- Có thể truy cập thông qua một trường toàn cầu, tĩnh;
- Được tạo hoặc khi khởi tạo chương trình hoặc khi truy cập lần đầu;
- Không có nhà xây dựng công cộng (không thể khởi tạo trực tiếp);
- Không bao giờ được giải phóng rõ ràng (hoàn toàn giải phóng khi chấm dứt chương trình).
Chính vì sự lựa chọn thiết kế cụ thể này mà mẫu này đưa ra một số vấn đề dài hạn tiềm ẩn:
- Không có khả năng sử dụng các lớp trừu tượng hoặc giao diện;
- Không có khả năng phân lớp;
- Khớp nối cao trên ứng dụng (khó sửa đổi);
- Khó kiểm tra (không thể giả / giả trong các bài kiểm tra đơn vị);
- Khó song song trong trường hợp trạng thái đột biến (yêu cầu khóa mở rộng);
- vân vân
Không có triệu chứng nào trong số này thực sự là đặc hữu của các trường hợp đơn lẻ, chỉ là mẫu Singleton.
Bạn có thể làm gì thay thế? Đơn giản là đừng sử dụng mẫu Singleton.
Trích dẫn từ câu hỏi:
Ý tưởng là có một vị trí này trong ứng dụng giữ dữ liệu được lưu trữ và đồng bộ hóa, và sau đó bất kỳ màn hình mới nào được mở có thể chỉ cần truy vấn hầu hết những gì họ cần từ đó, mà không yêu cầu lặp lại các dữ liệu hỗ trợ khác nhau từ máy chủ. Liên tục yêu cầu máy chủ sẽ mất quá nhiều băng thông - và tôi đang nói thêm hàng ngàn đô la hóa đơn Internet mỗi tuần, vì vậy điều đó không thể chấp nhận được.
Khái niệm này có một cái tên, như bạn sắp xếp gợi ý nhưng âm thanh không chắc chắn. Nó được gọi là bộ đệm . Nếu bạn muốn nhận được sự ưa thích, bạn có thể gọi nó là "bộ đệm ngoại tuyến" hoặc chỉ là một bản sao ngoại tuyến của dữ liệu từ xa.
Một bộ đệm không cần phải là một singleton. Nó có thể cần phải là một phiên bản duy nhất nếu bạn muốn tránh tìm nạp cùng một dữ liệu cho nhiều phiên bản bộ đệm; nhưng điều đó không có nghĩa là bạn thực sự phải phơi bày mọi thứ với mọi người .
Điều đầu tiên tôi làm là tách các khu vực chức năng khác nhau của bộ đệm thành các giao diện riêng biệt. Ví dụ: giả sử bạn đang tạo bản sao YouTube tồi tệ nhất thế giới dựa trên Microsoft Access:
MSAccessCache
▲
|
+ ----------------- + ----------------- +
| | |
IMediaCache IProfileCache IPageCache
| | |
| | |
VideoPage MyAccountPage MostP phổ biếnPage
Ở đây bạn có một vài giao diện mô tả cụ thể các loại dữ liệu một lớp học đặc biệt có thể cần truy cập vào - phương tiện truyền thông, hồ sơ người dùng, và các trang tĩnh (như trang bìa). Tất cả điều đó được thực hiện bởi một mega-cache, nhưng bạn thiết kế các lớp riêng lẻ của mình để chấp nhận các giao diện thay vào đó, vì vậy chúng không quan tâm loại cá thể nào chúng có. Bạn khởi tạo thể hiện vật lý một lần, khi chương trình của bạn bắt đầu, và sau đó chỉ bắt đầu chuyển qua các thể hiện (chuyển sang một loại giao diện cụ thể) thông qua các hàm tạo và thuộc tính công cộng.
Nhân tiện, đây được gọi là Tiêm phụ thuộc ; bạn không cần sử dụng Spring hoặc bất kỳ bộ chứa IoC đặc biệt nào, miễn là thiết kế lớp chung của bạn chấp nhận sự phụ thuộc của nó từ người gọi thay vì khởi tạo chúng trên trạng thái toàn cầu hoặc tham chiếu toàn bộ .
Tại sao bạn nên sử dụng thiết kế dựa trên giao diện? Ba lý do:
Nó làm cho mã dễ đọc hơn; bạn có thể hiểu rõ ràng từ các giao diện chính xác dữ liệu mà các lớp phụ thuộc phụ thuộc vào.
Nếu và khi bạn nhận ra rằng Microsoft Access không phải là lựa chọn tốt nhất cho back-end dữ liệu, bạn có thể thay thế nó bằng thứ gì đó tốt hơn - giả sử SQL Server.
Nếu và khi bạn nhận ra rằng SQL Server không phải là lựa chọn tốt nhất cho phương tiện truyền thông đặc biệt , bạn có thể chia tay thực hiện của bạn mà không ảnh hưởng bất kỳ một phần khác của hệ thống . Đó là nơi sức mạnh thực sự của sự trừu tượng đến.
Nếu bạn muốn tiến thêm một bước thì bạn có thể sử dụng bộ chứa IoC (khung DI) như Spring (Java) hoặc Unity (.NET). Hầu hết mọi khung DI sẽ thực hiện quản lý trọn đời của riêng nó và đặc biệt cho phép bạn xác định một dịch vụ cụ thể là một thể hiện duy nhất (thường gọi nó là "singleton", nhưng đó chỉ là sự quen thuộc). Về cơ bản các khung này giúp bạn tiết kiệm phần lớn công việc của khỉ khi chuyển thủ công xung quanh các trường hợp, nhưng chúng không thực sự cần thiết. Bạn không cần bất kỳ công cụ đặc biệt nào để thực hiện thiết kế này.
Để hoàn thiện, tôi nên chỉ ra rằng thiết kế ở trên thực sự không lý tưởng. Khi bạn đang xử lý một bộ đệm (như bạn), bạn thực sự nên có một lớp hoàn toàn riêng biệt . Nói cách khác, một thiết kế như thế này:
+ - Kho lưu trữ IMedia
|
Bộ nhớ cache (Chung) --------------- + - IProfileRep repository
▲ |
| + - Kho lưu trữ IPage
+ ----------------- + ----------------- +
| | |
IMediaCache IProfileCache IPageCache
| | |
| | |
VideoPage MyAccountPage MostP phổ biếnPage
Lợi ích của việc này là bạn thậm chí không bao giờ cần phải phá vỡ Cache
trường hợp của mình nếu bạn quyết định tái cấu trúc; bạn có thể thay đổi cách Media được lưu trữ đơn giản bằng cách cung cấp cho nó một triển khai thay thế IMediaRepository
. Nếu bạn nghĩ về việc làm thế nào điều này khớp với nhau, bạn sẽ thấy rằng nó vẫn chỉ tạo ra một thể hiện vật lý của bộ đệm, vì vậy bạn không bao giờ cần phải tìm nạp cùng một dữ liệu hai lần.
Không có gì trong số này để nói rằng mọi phần mềm duy nhất trên thế giới cần phải được kiến trúc theo các tiêu chuẩn chính xác này về sự gắn kết cao và khớp nối lỏng lẻo; nó phụ thuộc vào quy mô và phạm vi của dự án, nhóm của bạn, ngân sách của bạn, thời hạn, v.v. Nhưng nếu bạn đang hỏi thiết kế tốt nhất là gì (để sử dụng thay cho một đơn), thì đây là nó.
PS Như những người khác đã tuyên bố, có lẽ không phải là ý tưởng tốt nhất cho các lớp phụ thuộc nhận thức được rằng họ đang sử dụng bộ đệm - đó là một chi tiết triển khai mà họ đơn giản không bao giờ nên quan tâm. Điều đó đang được nói, kiến trúc tổng thể vẫn sẽ trông rất giống với những gì trong hình trên, bạn sẽ không đề cập đến các giao diện riêng lẻ như Caches . Thay vào đó, bạn đặt tên cho chúng là Dịch vụ hoặc một cái gì đó tương tự.