2012-02-02 30 views
5

Tôi vừa hoàn thành cuốn sách của Mark Seemann Injection Dependency in .NET và bây giờ tôi đang cố gắng refactor một số mã cũ. (Tôi không, ở giai đoạn này, dựa vào bất kỳ thùng chứa DI cụ thể nào, thay vì chỉ cố di chuyển tất cả các phụ thuộc vào một nơi).Làm cách nào để áp dụng việc tiêm phụ thuộc vào một nhà máy trừu tượng

Tôi nhìn vào lớp nhà máy sau đó xác định ArchiveType bằng cách đọc vài byte đầu tiên của các kho lưu trữ với archiveReader.GetArchiveType() và sau đó trả về một thể hiện của một ArchiveRestorer dựa trên ArchiveType enum.

public class ArchiveRestorerFactory : IArchiveRestorerFactory 
{ 
    public ArchiveRestorer Create(ArchiveReader archiveReader) 
    { 
     ArchiveType type = archiveReader.GetArchiveType(); 
     switch (type) 
     { 
      case ArchiveType.CurrentData: 
       return new CurrentDataArchiveRestorer(archiveReader); 
       break; 
      case ArchiveType.HistoricalData: 
       return new HistoricalDataArchiveRestorer(archiveReader); 
       break; 
      case ArchiveType.AuditTrail: 
       return new AuditTrailArchiveRestorer(archiveReader); 
       break; 
      default: 
       throw new Exception("ArchiveRestorerFactory error: Unknown value for ArchiveType."); 
     } 
    } 
} 

Làm thế nào để cấu trúc lại này để các lớp không phụ thuộc vào các loại bê tông CurrentDataArchiveRestorer, HistoricalDataArchiveRestorerAuditTrailArchiveRestorer?

Tôi có nên di chuyển ba người khôi phục bê tông vào nhà xây dựng của nhà máy không?

public ArchiveRestorer Create(ArchiveReader archiveReader, 
    ArchiveRestorer currentDataArchiveRestorer, 
    ArchiveRestorer historicalDataArchiveRestorer, 
    ArchiveRestorer auditTrailDataArchiveRestorer) 
{ 
    // guard clauses... 
    // assign to readonly fields 
} 

Đó dường như là cách tiếp cận đề nghị here, nhưng sau đó nó sẽ nhanh chóng cả ba phục chế khi chỉ có một là cần thiết? Điều gì xảy ra nếu tôi có 20 cách triển khai cụ thể khác nhau có thể thay thế?

Tôi cảm thấy như tôi nên triển khai một nhà máy cụ thể cho từng loại nhà phục chế và trả lại thay vào đó nhưng sau đó tôi chỉ thay thế new bằng một loại khác.

Cách tốt nhất để cấu trúc lại cái này là gì?

+1

Tôi nghĩ kịch bản của bạn có thể phù hợp hơn với một chuỗi mô hình trách nhiệm. Xem [ví dụ này] (http://davidhayden.com/blog/dave/archive/2008/11/19/ChainResponsibilityDesignPatternUnityDependencyInjectionContainer.aspx) để sử dụng mẫu cùng với một vùng chứa DI (Unity) cụ thể. –

+0

Tôi sẽ không thực hiện việc đăng ký và lắp ráp chuỗi theo cách đó, nhưng nó chắc chắn là một cách tiếp cận hợp lệ. –

+0

Ngoài việc sử dụng 'thừa'? 'Của 'enum', điều gì đặc biệt làm phiền bạn về việc triển khai hiện tại của bạn? –

Trả lời

2

Cách tôi làm điều này, với mã bạn đã có, sẽ tạo một nhà máy cho từng đối tượng có phương pháp Create().

Tôi cũng có giao diện cho các nhà máy này và để họ kế thừa từ giao diện nhà máy chung.

Sau đó, bạn có thể sử dụng giao diện làm điểm để tiêm vào hàm tạo của mình.

nào sẽ được gọi là tương tự như sau:

case ArchiveType.CurrentData: 
       return _currentDateArchiveRestorerFactory.Create(archiveReader); 
       break; 

Ngoài ra, nó có thể là tốt hơn để có một nhà máy duy nhất tạo ra một thể hiện của một loại nhất định. Vì tất cả các đối tượng này là những người khôi phục bạn chỉ có thể tạo cá thể dựa trên số enum thay vì một số switch.

_restorerFactory.Create(ArchiveType.CurrentData); 
1

Thực hiện một giao diện với một phương pháp với lợi nhuận kiểu giao diện đó và để cho ba lớp Archiver thực hiện giao diện đó và sau đó trong phương pháp tạo ra các loại tham số sẽ chỉ là giao diện và nó sẽ trả lại đối tượng được yêu cầu bằng cách gọi phương thức giao diện bạn vừa tạo. Vì vậy, bạn không cần loại bê tông trong phương thức tạo.

0
interface ILogger 
{ 
    void Log(string data); 
} 

class Logger : ILogger 
{ 
    . 
    . 
    . 
} 

Tại thời điểm này, bạn sử dụng một đối tượng trung gian nhà máy để trả lại logger để được sử dụng trong các thành phần:

class MyComponent 
{ 
    void DoSomeWork() 
    { 
    // Get an instance of the logger 
    ILogger logger = Helpers.GetLogger(); 
    // Get data to log 
    string data = GetData(); 

    // Log 
    logger.Log(data); 
    } 
} 

class Helpers 
{ 
    public static ILogger GetLogger() 
    { 
    // Here, use any sophisticated logic you like 
    // to determine the right logger to instantiate. 

    ILogger logger = null; 
    if (UseDatabaseLogger) 
    { 
     logger = new DatabaseLogger(); 
    } 
    else 
    { 
     logger = new FileLogger(); 
    } 
    return logger; 
    } 
} 
class FileLogger : ILogger 
{ 
    . 
    . 
    . 
} 

class DatabaseLogger : ILogger 
{ 
    . 
    . 
    . 
} 
2

Tại sao không làm cho ArchiveReader chịu trách nhiệm tạo ArchiveRestorer thích hợp?Sau đó, phiên đầu tiên của mã sẽ trông như thế này:

public class ArchiveRestorerFactory : IArchiveRestorerFactory 
{ 
    public ArchiveRestorer Create(ArchiveReader archiveReader) 
    { 
     ArchiveRestorer restorer = archiveReader.GetArchiveRestorer(); 
     return restorer; 
    } 
} 

Đến lúc đó, nó nên được khá rõ ràng rằng các nhà máy là không cần thiết, vì vậy trong lần lặp thứ hai của mã bạn có thể vứt nó đi để cho người tiêu dùng gọi trực tiếp ArchiveReader.

+0

Điều đó nghe có vẻ giống như một phép tái cấu trúc xuất sắc và tôi sẽ thực hiện nó, nhưng nó không giải quyết vấn đề phụ thuộc. Nó di chuyển các phụ thuộc vào lớp 'ArchiveReader'. 'ArchiveReader.GetArchiveRestorer()' sẽ vẫn cần 'new' lên lớp con đúng của' ArchiveRestorer'. – shamp00

+1

Tiêm chúng vào ArchiveReader. Tất cả đều tóm tắt cách nó chọn loại phụ thích hợp. Vì bạn chưa chia sẻ điều đó, có một chút khó trả lời. Tuy nhiên, nếu bạn quyết định chia sẻ điều đó, nó sẽ là một câu hỏi mới ở đây trên SO. –

+0

Điều này không giải quyết được vấn đề phụ thuộc (như đã đề cập trong phần bình luận ở trên) và cũng có thể phá vỡ SRP? Im hiện đang đọc sách của bạn nhưng tôi đang bắt kịp với những điều này khi cố gắng áp dụng các lý thuyết vào mã thực. – Steve

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