Câu trả lời dưới đây là sai, nhưng tôi sẽ giữ nó để người khác học hỏi từ nó (xem bên dưới)
Trong ExampleA
, bạn có thể sử dụng cùng một Config
thể hiện trên nhiều lớp. Tuy nhiên, nếu chỉ có một Config
phiên bản trong toàn bộ ứng dụng, hãy xem xét áp dụng mẫu Singleton trên Config
để tránh có nhiều phiên bản Config
. Và nếu Config
là Singleton, bạn có thể thực hiện các thao tác sau:
class ExampleA
{
private $config;
public function __construct()
{
$this->config = Config->getInstance();
}
}
$exampleA = new ExampleA();
Trong ExampleB
, mặt khác, bạn sẽ luôn có được một trường hợp riêng biệt của Config
từng thể hiện của ExampleB
.
Phiên bản nào bạn nên áp dụng thực sự phụ thuộc vào cách ứng dụng sẽ xử lý các trường hợp Config
:
- nếu mỗi trường hợp
ExampleX
nên có một thể hiện riêng biệt Config
, hãy đi với ExampleB
;
- nếu mỗi phiên bản
ExampleX
sẽ chia sẻ một (và chỉ một) phiên bản của Config
, sử dụng ExampleA with Config Singleton
;
- nếu các trường hợp
ExampleX
có thể sử dụng các trường hợp khác nhau Config
, hãy gắn bó với ExampleA
.
Tại sao chuyển đổi Config
thành Singleton là sai:
Tôi phải thừa nhận rằng tôi chỉ học về mẫu Singleton ngày hôm qua (đọc cuốn sách Head First về các mẫu thiết kế). Chắc chắn tôi đã đi và áp dụng nó cho ví dụ này, nhưng như nhiều người đã chỉ ra, một cách là một cách khác (một số đã khó hiểu hơn và chỉ nói "Bạn đang làm sai!"), Đây không phải là một ý tưởng tốt. Vì vậy, để ngăn người khác mắc lỗi tương tự mà tôi vừa mắc phải, dưới đây là tóm tắt lý do tại sao mẫu Singleton có thể gây hại (dựa trên các nhận xét và những gì tôi đã phát hiện ra)
Nếu ExampleA
lấy tham chiếu riêng của nó đến Config
thể hiện, các lớp sẽ được liên kết chặt chẽ. Sẽ không có cách nào để có một ExampleA
phiên bản sử dụng một phiên bản khác của Config
(giả sử một số lớp con). Điều này thật kinh khủng nếu bạn muốn kiểm tra ExampleA
bằng cách sử dụng một ví dụ giả Config
vì không có cách nào để cung cấp nó ExampleA
.
Tiền đề của việc sẽ có một, và chỉ một, ví dụ Config
có thể nắm giữ ngay bây giờ , nhưng bạn không thể luôn chắc chắn rằng điều tương tự sẽ giữ trong tương lai . Nếu tại một thời điểm nào đó, nó chỉ ra rằng nhiều trường hợp Config
sẽ được mong muốn, không có cách nào để đạt được điều này mà không cần viết lại mã.
Mặc dù trường hợp một và chỉ một Config
có thể đúng với mọi thời đại, nhưng có thể xảy ra rằng bạn muốn có thể sử dụng một số lớp con của Config
(trong khi vẫn chỉ có một thể hiện). Nhưng, kể từ khi mã trực tiếp được thể hiện qua getInstance()
các Config
, mà là một static
phương pháp, không có cách nào để có được những lớp con. Một lần nữa, mã phải được viết lại.
Thực tế là việc ExampleA
sử dụng Config
sẽ bị ẩn, ít nhất là khi chỉ xem API của ExampleA
. Điều này có thể hoặc không phải là một điều xấu, nhưng cá nhân tôi cảm thấy rằng điều này cảm thấy như một bất lợi; chẳng hạn, khi duy trì, không có cách đơn giản nào để tìm ra lớp nào sẽ bị ảnh hưởng bởi các thay đổi Config
mà không xem xét việc thực hiện của mọi lớp khác.
Ngay cả khi việc ExampleA
sử dụng Singleton Config
không phải là vấn đề trong chính nó, nó vẫn có thể trở thành vấn đề từ quan điểm thử nghiệm. Các đối tượng Singleton sẽ mang trạng thái sẽ tồn tại cho đến khi chấm dứt ứng dụng. Đây có thể là một vấn đề khi chạy thử nghiệm đơn vị vì bạn muốn tách biệt một thử nghiệm với một thử nghiệm khác (nghĩa là đã thực hiện một thử nghiệm này sẽ không ảnh hưởng đến kết quả của thử nghiệm khác). Để khắc phục điều này, đối tượng Singleton phải bị hủy giữa mỗi lần chạy thử (có khả năng phải khởi động lại toàn bộ ứng dụng), điều này có thể tốn thời gian (không đề cập đến tẻ nhạt và gây phiền nhiễu).
Đã nói điều này, tôi rất vui vì tôi đã phạm sai lầm này ở đây và không phải trong việc thực hiện một ứng dụng thực sự. Trong thực tế, tôi đã thực sự xem xét việc viết lại mã mới nhất của mình để sử dụng mẫu Singleton cho một số lớp. Mặc dù tôi có thể dễ dàng hoàn nguyên các thay đổi (tất nhiên mọi thứ được lưu trữ trong SVN), tôi vẫn sẽ lãng phí thời gian để thực hiện.