2010-02-25 23 views
11

Tôi dường như bị kẹt trong một tình huống khó xử về mô hình Flyweight.Vấn đề về Flyweight và Factory với IDisposable

Trước tiên, hãy nói rằng tôi có một loại dùng một lần DisposableFiddle và một nhà máy FiddleFactory:

public interface DisposableFiddle : IDisposable 
{ 
    // Implements IDisposable 
} 

public class FiddleFactory 
{ 
    public DisposableFiddle CreateFiddle(SomethingThatDifferentiatesFiddles s) 
    { 
     // returns a newly created fiddle. 
    } 
} 

Sau đó, theo ý kiến ​​của tôi, nó khá rõ ràng đối với các khách hàng của FiddleFactory rằng nhà máy tuyên bố không có quyền sở hữu của fiddle tạo và rằng đó là trách nhiệm của khách hàng khi vứt bỏ fiddle khi thực hiện với nó.

Tuy nhiên, chúng ta hãy thay nói rằng tôi muốn chia sẻ fiddles giữa khách hàng bằng cách sử dụng các Flyweight pattern:

public class FiddleFactory 
{ 
    private Dictionary<SomethingThatDifferentiatesFiddles, DisposableFiddle> fiddles = new ...;   

    public DisposableFiddle CreateFiddle(SomethingThatDifferentiatesFiddles s) 
    { 
     // returns an existing fiddle if a corresponding s is found, 
     // or a newly created fiddle, after adding it to the dictionary, 
     // if no corresponding s is found. 
    } 
} 

Sau đó, tôi cảm thấy đạo đức bắt buộc phải làm cho các nhà máy riêng của mình dùng một lần, vì nó tạo ra fiddles và giữ tài liệu tham khảo cho họ trong suốt cuộc đời của họ. Nhưng điều đó sẽ gây ra vấn đề cho các khách hàng cho rằng họ sở hữu các câu đố và do đó nên vứt bỏ chúng.

là vấn đề thực sự mà tôi gọi là nhà máy FiddleFactory thay vì, nói, FiddlePool, và "sáng tạo" Phương pháp CreateFiddle thay vì GetFiddle? Như thế này:

public class FiddlePool : IDisposable 
{ 
    private Dictionary<SomethingThatDifferentiatesFiddles, DisposableFiddle> fiddles = new ...;   

    public DisposableFiddle GetFiddle(SomethingThatDifferentiatesFiddles s) 
    { 
     // returns an existing fiddle if a corresponding s is found, 
     // or a newly created fiddle, after adding it to the dictionary, 
     // if no corresponding s is found. 
    } 

    // Implements IDisposable 
} 

Sau đó, nó rõ ràng hơn với khách hàng rằng nó sẽ không sở hữu thẻ trả về và đó là trách nhiệm của hồ bơi để vứt bỏ các câu đố.

Hoặc điều này chỉ có thể dễ dàng được giải quyết bằng tài liệu?

Có cách nào thoát khỏi tình huống khó xử không? Thậm chí có một tình trạng tiến thoái lưỡng nan? :-)

Trả lời

7

tôi có thể thấy hai cách thoát khỏi vấn đề này:

  • ThreadPool kiểu: thiết kế lại lớp nên FiddlePool cung cấp một giao diện để làm những việc khó sử dụng. Hồ bơi không phát ra Fiddle trường hợp vì thay vào đó, phương thức này có phương thức FiddlePool.PlayFiddle. Kể từ khi hồ bơi kiểm soát cuộc sống fiddle, nó có trách nhiệm xử lý chúng.

  • SqlConnection kiểu: sửa đổi phương pháp xử lý công Fiddle 's để nó thực sự chỉ trả fiddles đến hồ bơi fiddle (mà lớp fiddle đóng gói). Bên trong, hồ bơi fiddle chăm sóc thực sự giải phóng tài nguyên dùng một lần.

+0

Cảm ơn, người đầu tiên tuân theo Luật Demeter tốt hơn và thứ hai phù hợp hơn trong thiết kế tổng thể của tôi. Hmmm ... –

+0

Tôi sẽ đặt hai xu của tôi vào cho phương pháp đầu tiên - Tôi đã nhìn thấy một quá nhiều người cố gắng để viết hồ bơi SqlConnnection của riêng mình! (Không hẳn, nhưng tôi * phải * giải thích tại sao nó không cần thiết.) –

2

Tôi đồng ý với ý kiến ​​thứ hai của bạn. Thuật ngữ 'Pool' và 'Get' làm cho mọi thứ rõ ràng hơn cho người tiêu dùng. Tuy nhiên, nó vẫn không làm cho mọi thứ rõ ràng đủ, và tài liệu cần phải luôn luôn được bổ sung để đảm bảo một sự hiểu biết đầy đủ, hợp lệ.

+3

Suy nghĩ của tôi chính xác. Ngoài ra, tôi có lẽ sẽ không gọi lớp học của bạn DisposableFiddle trừ khi bạn muốn người dùng Dispose() nó ... –

+0

@Reed: Đồng ý về DisposableFiddle. Việc đặt tên thích hợp là rất quan trọng để truyền đạt ý định, và là hàng phòng thủ đầu tiên chống lại việc sử dụng không chính xác. – jrista

+0

Heh, vâng, tôi chỉ prepended dùng một lần cho tên ví dụ để làm cho nó dễ dàng hơn để làm theo trong bước của tôi (nhầm lẫn) ... –

1

Bạn nên làm gì đó hơn là chỉ tài liệu và cách đặt tên để yêu cầu khách hàng không được vứt bỏ. Thực sự sẽ tốt hơn nếu để khách hàng gọi vứt bỏ để làm cho mô hình sử dụng. Đi một số hướng từ các hồ bơi kết nối cơ sở dữ liệu của chúng tôi được xây dựng.

Cơ sở dữ liệu chứa một loạt các kết nối mà bản thân họ nhận thức được.Mã cuộc gọi tạo ra một kết nối, mở nó và gọi gần (vứt bỏ) trên đó. Mã gọi không thực sự biết nếu nó được gộp chung hay không, tất cả được xử lý nội bộ bởi lớp kết nối. Với kết nối gộp, gọi Open() bị bỏ qua nếu kết nối đã được mở. Close()/Dispose() được gọi và trong trường hợp của một kết nối gộp, điều này thực sự trả về kết nối trở lại hồ bơi thay vì đóng nó.

Bạn có thể làm điều tương tự bằng cách tạo lớp PooledFiddle ghi đè Vứt bỏ và trả về đối tượng vào hồ bơi. Lý tưởng nhất là khách hàng thậm chí sẽ không phải biết đó là một Fiddle gộp lại.

+0

"Lý tưởng nhất là khách hàng thậm chí sẽ không biết đó là một Fiddle được gộp lại." - vâng, tôi đồng ý về điều đó. Tôi nghĩ rằng đó là một chi tiết thực hiện tốt hơn là ẩn. –

Các vấn đề liên quan