2009-03-31 33 views
16

Tôi tin rằng mẫu thiết kế phương thức nhà máy phù hợp với những gì tôi đang cố gắng làm, nhưng tôi không chắc chắn bao nhiêu trách nhiệm (kiến thức về các lớp con mà nó tạo ra) để cung cấp cho nó. Các ví dụ về cách sử dụng factory method pattern tại Wikipedia mô tả tình hình tôi đang ở gần như chính xác:Nhà máy biết loại đối tượng nào cần tạo?

public class ImageReaderFactory 
{ 
    public static ImageReader getImageReader(InputStream is) 
    { 
     int imageType = figureOutImageType(is); 

     switch(imageType) 
     { 
      case ImageReaderFactory.GIF: 
       return new GifReader(is); 
      case ImageReaderFactory.JPEG: 
       return new JpegReader(is); 
      // etc. 
     } 
    } 
} 

Câu hỏi của tôi là, những gì hiện các figureOutImageType chức năng như thế nào? Trong ví dụ cụ thể này, tôi giả định rằng nó sẽ kiểm tra tiêu đề của tệp trong số InputStream để xác định định dạng dữ liệu nào. Tôi muốn biết liệu số ImageReaderFactory có biết cách phân tích cú pháp tiêu đề tệp hay không và xác định xem loại tệp có phải là GIF hay không , JPEG, vv, hoặc nếu nó gọi một hàm bên trong mỗi lớp Reader cho phép nó biết loại hình ảnh đó là gì. Một cái gì đó như thế này, có lẽ:

int figureOutImageType(InputStream is) 
{ 
    if(GifReader.isGIF(is)) 
     return ImageReaderFactory.GIF; 
    else if(JpegReader.isJPEG(is)) 
     return ImageReaderFactory.JPEG; 
    // etc. 
} 

Nó có vẻ như có nhà máy biết làm thế nào để phân tích các hình ảnh vi phạm đóng gói, và cho phép các lớp con quyết định cái nào nên được tạo là một phần của các mẫu thiết kế phương pháp nhà máy. Tuy nhiên, nó cũng có vẻ như các chức năng figureOutImageType chỉ là thêm một số mã dự phòng, bởi vì tại sao không chỉ có mỗi phân lớp thực hiện kiểm tra của nó trên InputStream trong chức năng getImageReader và bỏ qua trường hợp chuyển đổi?

Tôi chưa từng có kinh nghiệm sử dụng các nhà máy trước đây và tôi hy vọng có được một số thông tin chi tiết từ một số người đã sử dụng chúng trong quá khứ theo cách tốt nhất để xử lý vấn đề này. Nhà máy có biết về hoạt động bên trong của các lớp con của nó hay không, hoặc họ có chịu trách nhiệm cho phép nhà máy biết tạo ra cái gì không và làm thế nào để bạn tổ chức nó?

Cảm ơn!

+0

Câu hỏi tuyệt vời, được suy nghĩ kỹ lưỡng. 1, nhiều hơn nếu nó chỉ có thể! – hmcclungiii

+0

Đồng ý. Câu hỏi hay. – Ankur

Trả lời

6

Nhà máy nên có một số ý tưởng về việc chọn đối tượng thực tế để tạo. Ví dụ, phương thức WebRequest.Create trong .NET, có thể chọn giữa các giao thức khách hàng khác nhau bằng cách kiểm tra phần giao thức của Uri. Nó không cần phân tích toàn bộ mọi thứ. Chỉ cần một phần được yêu cầu để phân biệt lớp nào sẽ chịu trách nhiệm về nó (trong ví dụ của bạn, nó có thể sẽ chỉ là tiêu đề của tệp).

Về câu hỏi của bạn về việc đóng gói, không thực sự ... Hầu hết thời gian, nhà máy được mã hóa cứng và đã biết về các loại lớp khác nhau và các tính năng của chúng. Nó đã phụ thuộc vào chức năng được cung cấp bởi một tập các lớp đã biết, vì vậy bạn không thêm nhiều vào nó. Bạn cũng có thể gói gọn phần phát hiện của nhà máy trong một lớp trợ giúp khác có thể được cả nhà máy lẫn các lớp con sử dụng (trong nguyên lý của nguyên tắc DRY).

+0

Cảm ơn bạn đã nhập. Vì vậy, bạn có thể khuyên tôi nên sử dụng một lớp trợ giúp/tiện ích được chia sẻ để xác định loại tệp từ InputStream trong hàm getImageReader và chỉ cần bật enum trả về? – Venesectrix

+0

Vâng, đây là một cách tiếp cận tốt. –

0

Tôi sẽ có phương thức tĩnh CanReadFrom (hoặc cái gì đó) trong giao diện phổ biến ImageReader (không chắc chắn nếu điều này là có thể - FIXME). Sử dụng sự phản chiếu để lấy tất cả những người triển khai và gọi hàm. Nếu một trả về true, trả về một thể hiện của lớp.

1

Để có thể mở rộng, bạn có thể mở rộng một số phụ thuộc mà bạn đề cập đến. Giống như tìm ra loại tệp hoặc ánh xạ loại tệp tới một lớp xử lý nó. Một đăng ký bên ngoài (tức là, tập tin thuộc tính) sẽ lưu trữ nói, GIF -> GifReader, hoặc GIF tốt hơn -> GifMetadataClass. Sau đó, mã của bạn có thể là chung chung và không có phụ thuộc vào tất cả các lớp, cộng với bạn có thể mở rộng nó trong tương lai, hoặc các bên thứ ba có thể mở rộng nó.

+0

Tôi nghĩ rằng bạn đang nói rằng tôi có thể sử dụng một bản đồ để liên kết một loại tệp với một lớp xử lý loại tệp đó, đúng không? Nhà máy sẽ xác định loại tệp nào dựa trên InputStream trong trường hợp này? Tôi không chắc bạn có thể thiết lập bản đồ từ InputStream đến loại tệp hay không. – Venesectrix

+0

Từ luồng đầu vào, rất nhiều các lớp hình ảnh này có số ma thuật ngay từ đầu hoặc ít nhất là một cái gì đó chung chung mà bạn có thể chuyển qua để trích xuất loại hình ảnh. –

+0

Đó là sự thật. Tôi thấy những gì bạn đang nói về làm cho nó chung chung và mở rộng bằng cách sử dụng các hiệp hội, mà chắc chắn là một cái gì đó để xem xét. Trong trường hợp cụ thể của tôi nó có thể không có giá trị nó, bởi vì tôi chỉ có một vài đối tượng khác nhau được tạo ra và không lường trước được nhiều hơn được thêm vào. – Venesectrix

1

Nếu đây là cửa sổ, tôi sẽ thử đoán loại nội dung và sau đó sử dụng nhà máy. Trong thực tế, tôi đã làm điều này một thời gian trước đây.

Dưới đây là một lớp học để đoán kiểu nội dung của một tập tin:

using System; 
using System.IO; 
using System.Runtime.InteropServices; 

namespace Nexum.Abor.Common 
{ 
    /// <summary> 
    /// This will work only on windows 
    /// </summary> 
    public class MimeTypeFinder 
    { 
     [DllImport(@"urlmon.dll", CharSet = CharSet.Auto)] 
     private extern static UInt32 FindMimeFromData(
      UInt32 pBC, 
      [MarshalAs(UnmanagedType.LPStr)] String pwzUrl, 
      [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer, 
      UInt32 cbSize, 
      [MarshalAs(UnmanagedType.LPStr)]String pwzMimeProposed, 
      UInt32 dwMimeFlags, 
      out UInt32 ppwzMimeOut, 
      UInt32 dwReserverd 
     ); 

     public string getMimeFromFile(string filename) 
     { 
      if (!File.Exists(filename)) 
       throw new FileNotFoundException(filename + " not found"); 

      var buffer = new byte[256]; 
      using (var fs = new FileStream(filename, FileMode.Open)) 
      { 
       if (fs.Length >= 256) 
        fs.Read(buffer, 0, 256); 
       else 
        fs.Read(buffer, 0, (int)fs.Length); 
      } 
      try 
      { 
       UInt32 mimetype; 
       FindMimeFromData(0, null, buffer, 256, null, 0, out mimetype, 0); 
       var mimeTypePtr = new IntPtr(mimetype); 
       var mime = Marshal.PtrToStringUni(mimeTypePtr); 
       Marshal.FreeCoTaskMem(mimeTypePtr); 
       return mime; 
      } 
      catch (Exception) 
      { 
       return "unknown/unknown"; 
      } 
     } 
    } 
} 
+0

Chúng có bất kỳ hàm tra cứu MIME nào trong .Net hay là Windows API gọi giải pháp duy nhất thiếu lưu trữ bảng tra cứu của riêng bạn. – James

+0

Theo hiểu biết của tôi, không có phát hiện loại mime nào trong .NET –

2

Cả hai đều là những lựa chọn hợp lệ tùy thuộc vào ngữ cảnh.

NẾU bạn là kiến ​​trúc sư cho khả năng mở rộng - hãy nói mô hình plugin cho các Trình tạo hình ảnh khác nhau - thì lớp Nhà máy của bạn không thể biết về tất cả các ImageReaders có thể. Trong trường hợp đó, bạn đi theo tuyến đường ImageReader.CanRead(ImageStream) - yêu cầu từng người triển khai cho đến khi bạn tìm thấy người thực hiện có thể đọc nó.

Hãy coi chừng, đôi khi việc đặt hàng đó không quan trọng ở đây. Bạn có thể có GenericImageReader có thể xử lý JPG, nhưng Jpeg2000ImageReader tốt hơn ở đó. Đi bộ các nhà triển khai ImageReader sẽ dừng lại ở bất cứ nơi nào trước tiên. Bạn có thể muốn xem xét sắp xếp danh sách các ImageReaders có thể nếu đó là vấn đề.

Nếu không, nếu danh sách ImageReaders là hữu hạn và dưới sự kiểm soát của bạn, thì bạn có thể đi theo cách tiếp cận Nhà máy truyền thống hơn. Trong trường hợp đó, Nhà máy quyết định những gì cần tạo. Nó đã được kết hợp với các triển khai cụ thể của ImageReader bởi ctor, vì vậy việc thêm các quy tắc cho mỗi ImageReader không làm tăng sự ghép nối. Nếu logic để chọn ImageReader chủ yếu trong ImageReader, thì để tránh trùng lặp mã, bạn vẫn có thể đi theo tuyến đường ImageReader.CanRead(ImageStream) - nhưng nó có thể chỉ được mã hóa cứng mà bạn đi bộ.

+0

Cảm ơn bạn đã trả lời! Tôi đang thực sự sử dụng C++, và tôi tin rằng tôi chỉ có tùy chọn đi bộ các loại ImageReader theo cách thủ công. Tôi không biết cách nào để xác định những lớp con nào có một lớp cơ sở ngoại trừ việc theo dõi chúng một cách cụ thể trong mã (mã hoá cứng hoặc được thêm vào một mảng, v.v.) – Venesectrix

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