2010-01-19 4 views
8

Điều này là để phản hồi một số nhận xét trong what is so bad about singletonsLàm cách nào để sử dụng mẫu proxy để thay thế một singleton?

Có thể sử dụng mẫu proxy thay vì dữ liệu DB đơn lẻ. Nhưng tôi không thể thấy được lợi thế, và trên thực tế, singleton có vẻ "dễ kiểm soát" hơn.

Hãy để tôi giải thích rõ vấn đề. Giả sử bạn có một cơ sở dữ liệu, với một tập dữ liệu lớn, không bao giờ thay đổi để nó có thể được coi chỉ đọc, tại sao mẫu proxy lại là cách tốt hơn để mô hình hóa bộ nhớ cache dữ liệu này so với singleton?

(PS: nếu bạn đang đi để nói "bởi vì nó thêm 'kiểm chứng'!" - xin hãy giải thích, tôi vẫn quen với những khái niệm)

Nhờ sự giúp đỡ của bạn!

+3

mẫu thiết kế mindmap: http://www.mindmeister.com/7008138/design-patterns – jldupont

Trả lời

7

từ chối trách nhiệm: Tôi đang nói về java đây

singleton hiện đang được coi là một antipattern chủ yếu là bởi vì đã bị lạm dụng rất nhiều thời gian gần đây như họ là một cách nhanh chóng và thuận tiện để chia sẻ dữ liệu giữa các ứng dụng - đó là hơi một overextension của mẫu thiết kế đó là phù hợp hơn để cung cấp acces kiểm soát một tài nguyên được chia sẻ.

xem xét đầu ra tiêu chuẩn của chương trình: quyền truy cập tài nguyên đó cần được bảo vệ bởi một điểm truy cập duy nhất để cho phép đồng bộ hóa ghi, đó là lý do tại sao bạn có ví dụ System.out dưới dạng đối tượng tĩnh trong java.

vấn đề là, khi bạn bắt đầu có singleton bạn sẽ cần phải biết mọi chi tiết gritty nitty của những gì bạn đang làm, bởi vì bạn đang làm rất nhiều giả định nghiêm ngặt về lớp singleton của bạn, quan trọng nhất mà nó sẽ là lớp duy nhất trong hệ thống. sau đó bạn bắt đầu sử dụng nó, giả sử rằng nó sẽ luôn là một điểm vào tài nguyên của bạn, và sau đó lỗi khó chịu phát sinh vì lớp của bạn hiện đã được triển khai trên máy chủ ejb và mỗi ngữ cảnh ejb có singleton riêng, cộng thêm một singleton nữa mỗi jsp đã được tải lại từ máy chủ, cộng với một singleton cho mỗi lần singleton của bạn đã được tuần tự hóa và deserialized (như bạn có thể đã quên ghi đè phương thức readResolve()).

vì vậy đây là lý do tại sao singleton phải được sử dụng với rất nhiều dịch vụ chăm sóc và hiện được coi là một mẫu đối tượng mặc dù chúng hoàn toàn hữu ích cho mục đích sử dụng của chúng.

trong trường hợp bộ đệm cơ sở dữ liệu, sẽ là cách tiếp cận tốt hơn để yêu cầu bộ nhớ cache sử dụng proxy cho tài nguyên "cache" này, vì vậy bạn có thể thêm logic để "tìm tài nguyên" trong bản thân proxy thay vì có logic được gắn với việc truy xuất bộ nhớ cache singleton, có thể có hoặc không hoạt động tùy thuộc vào môi trường.

vì vậy trong vài từ sử dụng singleton như phương tiện để có quyền truy cập chia sẻ tài nguyên là xấu, bởi vì bạn đang hardcoding phương pháp tìm tài nguyên (và bỏ qua các bẫy đơn) trong khi có singleton để kiểm soát tài nguyên cho mục đích đồng bộ hóa là hoàn toàn chấp nhận được.

nghĩ về các ẩn dụ, những công trình này chỉ hoạt động nếu bạn có thể nhận được cùng một semaphore luôn. trong trường hợp thứ hai này có thể là vấn đề khi truy cập singleton từ mọi nơi bạn cần truy cập semaphore: ở đây bạn sẽ cần một lớp để bọc singleton lên và cung cấp sự kiểm soát tốt hơn vòng đời của semaphore.

proxy nhằm đảm bảo vai trò "cung cấp tài nguyên trên toàn hệ thống", có thể là một ứng dụng đơn lẻ, hệ thống máy chủ ứng dụng, các thành phần khác nhau của cùng một hệ thống và như vậy, với lợi ích bổ sung với èrpxy phương pháp truy xuất tài nguyên là mờ đục. bạn có thể yêu cầu họ cung cấp cho bạn một singleton chứa một hashmap của các giá trị được lưu trữ, bạn có thể cho họ truy cập vào memcached somwhere trên mạng, bạn có thể cho họ đọc một csv trong các bài kiểm tra, tất cả mà không thay đổi cách bạn gọi chúng từ ứng dụng.

+0

Xin chào, một số điểm tốt. Vấn đề tôi có là tôi không muốn cấu hình DB được phân tích cú pháp mỗi khi ai đó muốn truy cập dữ liệu được lưu trong bộ nhớ cache này, vì điều này là chậm. Populating bộ nhớ cache cũng là một quá trình chậm-ish. Trước đây, mọi yêu cầu mất khoảng 7 giây, bây giờ ít hơn 1. (Bây giờ chỉ có yêu cầu đầu tiên là chậm, từ đó trở đi, bạn không nhận thấy). Tôi thích điểm mà mẫu proxy không cần quan tâm đến vị trí của bộ nhớ cache và giảm sự phụ thuộc giữa ứng dụng. –

+1

Tất nhiên bộ nhớ cache là một loại tài nguyên cụ thể có lợi cho cả tính khả dụng của toàn hệ thống và truy cập mờ. đối với loại sự cố này, mẫu thứ ba có thể được sử dụng: dịch vụ được đặt tên được lưu trữ trong một thư mục. bạn có thể thấy mô hình này rất nhiều trong ejb và javaEE nói chung, sử dụng lớp InitialContext, nhưng bạn có thể có rất nhiều loại ngữ cảnh khác nhau. dài câu chuyện: bạn có ứng dụng của bạn tạo bộ nhớ cache như singleton lúc khởi động, đăng ký nó bên trong một bối cảnh dưới một tên được biết (tưởng tượng một ràng buộc rmi) và sau đó bạn có thể tạo một proxy để truy cập vào bối cảnh này để lấy bộ nhớ cache –

0

Tôi chỉ có thể tưởng tượng rằng Mẫu proxy được sử dụng để Proxy giữa Dữ liệu được lưu trong bộ nhớ cache và tải Dữ liệu (còn gọi là tải xuống lười).

Sắp xếp của:

class DbProxy 
{ 
    private static Data cache = null; // Sort-of Singleton 

    public static Data GetData(String query) 
    { 
    if (DbProxy.cache == null) 
    { 
     // Data = Do Stuff to read Data 
     DbProxy.cache = Data; 
    } 
    return DbProxy.cache; 
    } 
} 

này có ưu điểm là Bộ luật sử dụng này không nhất thiết phải quan tâm đến thời tiết các dữ liệu đã tồn tại thì chỉ có gọi GetData và thực hiện.

/* Disclaimer: Mã không hợp lệ, nó chỉ là giả chỉ dành riêng cho mục đích trình diễn */

+0

Có, nhưng đối với tôi, nó trông giống như một singleton. Có lẽ singleton của tôi đã là một proxy? –

+1

Tôi không có chuyên gia về các mẫu thiết kế và tôi không có bằng cấp CS hoặc bất cứ điều gì, vì vậy tôi có thể sai, nhưng với kiến ​​thức của tôi, các mẫu đó khá liên quan. Mẫu Proxy chỉ có thể hoạt động nhiều hơn (ví dụ: kiểm tra xem kết quả có thể lưu vào bộ nhớ cache hay không, nếu không phải lúc nào cũng lặp lại truy vấn thay vì trả về mục được lưu trong bộ nhớ cache). – dbemerlin

2

Theo tôi, không có "một trong hai, hoặc". Một lớp có thể thực hiện một số mẫu thiết kế cùng một lúc. Tôi sẽ nói rằng lớp thực hiện truy cập vào cơ sở dữ liệu bên ngoài là trong mọi trường hợp một Proxy (một proxy từ xa trong trường hợp này). Nếu bạn xem xét bộ đệm ẩn một chức năng phụ, nó cũng là một trang trí.

Vì vậy, câu hỏi thực sự là, nó cũng nên là Singleton? Chúng ta hãy giả sử có chính xác một cơ sở dữ liệu bên ngoài. Có cần phải chỉ có một CachingDBProxy? Tôi sẽ nói, nó phụ thuộc vào việc sử dụng:

Nếu có nhiều khách hàng truy cập dữ liệu tương tự, họ có thể hưởng lợi rõ ràng nếu họ chia sẻ cùng CachingDBProxy. Dữ liệu cần thiết bởi một máy khách có thể đã được cần bởi một máy khách khác, vì vậy nó có thể được lấy ra từ bộ nhớ cache thay vì phải thực hiện truy cập tốn kém vào cơ sở dữ liệu.

Mặt khác, một số khách hàng có thể truy cập các phần dữ liệu khá khác biệt. Vì vậy, nếu chúng ta giả định rằng CachingDBProxy chỉ lưu trữ một số lượng hạn chế truy cập dữ liệu bởi một nhóm khách hàng có thể ném ra dữ liệu vẫn còn cần thiết bởi một nhóm khách hàng khác, gây ra sự suy giảm hiệu suất bộ nhớ cache. Trong trường hợp này nó có thể là hợp lý để có nhiều CachingDBProxies mặc dù chỉ có một cơ sở dữ liệu (điều này giả định tất nhiên, truy cập đồng thời là có thể).

Vì vậy, cần có bao nhiêu CachingDBProxies, phụ thuộc vào việc sử dụng. CachingDBProxy không nên hạn chế việc sử dụng nó mà không có lý do chính đáng, vì vậy nó không nên thực thi rằng chỉ có một cá thể, Vì vậy, trong trường hợp này, CachingDBProxies không nên là Singleton, IMHO. Chỉ có các khách hàng mới biết được có bao nhiêu CachingDBProxies là tốt cho họ.

Mặt khác, nếu chúng tôi có một Proxy cho tài nguyên cụ thể mà chỉ có thể xử lý một truy cập tại một thời điểm, nó có thể phải là một Singleton. Nhưng đó là một trường hợp riêng biệt từ trường hợp trên. Ở đây yêu cầu đến trực tiếp từ khu vực mà Proxy chịu trách nhiệm (mục đích của nó là truy cập kênh vào tài nguyên cụ thể đó).

+0

Vâng, tôi thấy quan điểm của bạn. Tôi đoán nếu bạn phân tích thiết kế của hầu hết các lớp học, chúng sẽ bật ra để thực hiện một số mẫu, tất cả được nghiền thành một. –