2012-04-25 55 views
2

Short question

我應該在哪裏放抽象工廠界面和實際工廠?在哪個庫中應該定義抽象工廠接口和實際工廠?

概述

我正在寫一個簡單的視頻轉碼應用和我試圖環繞依賴注入我的頭。

我已經將我的應用程序分成了幾個Visual Studio工程。

  • 一個類庫的代碼轉換器,由應用程序引擎
  • 使用
  • 一個類庫將由GUI或控制檯接口
  • 一個控制檯應用程序使用的應用程序引擎,將是主要用戶接口現在

沒有DI

這就是一切看起來像依賴注入之前

轉碼器的lib:

namespace SimpleFFmpeg { 
    public interface ITranscoder { 
     void Transcode(String fileName); 

    } 

    public class Transcoder:ITranscoder { 
     // ... 

     public void Transcode(String fileName) { 
      // do transcoding stuff 
     } 

     // ... 
    } 
} 

的PusherEngine LIB:

using SimpleFFmpeg; 
namespace PusherLib { 
    public class PusherEngine { 
     private readonly List<VideoItem> _items; 

     public PusherEngine() { 
      _items = new List<VideoItem>(); 
     } 

     // ... 

     public void processItems() { 
      foreach (VideoItem item in _items) { 
       ITranscoder t = new Transcoder(); 
       t.Transcode(item.FileName); 
      } 
     } 

     // ... 
    } 
} 

實際應用:

namespace Pusher { 
    class Program { 
     static void Main(string[] args) { 
      PusherEngine pe = new PusherEngine(); 
      pe.addVideoItem(new VideoItem(...)); 
      pe.processItems(); 
     } 
    } 
} 

重構使用DI

我創建一個通用的抽象工廠界面,就像這個問題中提出的那樣: Creating new instances while still using Dependency Injection

public interface IFactory<T> { 
    T Get(); 
} 

接下來我創建了一個工廠,創建ITranscoders

public class TranscoderFactory: IFactory<ITranscoder> { 
    public ITranscoder Get() { 
     return new SimpleFFmpeg.Transcoder(); 
    } 
} 

然後我修改PusherEngine需要在構造一個工廠的依賴:

using SimpleFFmpeg; 
namespace PusherLib { 
    public class PusherEngine { 
     private readonly IFactory<ITranscoder> _transcoderFactory; 
     private readonly List<VideoItem> _items; 

     public PusherEngine(IFactory<ITranscoder> transcoderFactory) { 
      _items = new List<VideoItem>(); 
      _transcoderFactory = transcoderFactory; 
     } 

     // ... 

     public void processItems() { 
      foreach (VideoItem item in _items) { 
       ITranscoder t = _transcoderFactory.Get(); 
       t.Transcode(item.FileName); 
      } 
     } 

     // ... 
    } 
} 

最後,在計劃它看起來像這樣:

namespace Pusher { 
    class Program { 
     static void Main(string[] args) { 
      IFactory<ITranscoder> f = new TranscoderFactory(); 
      PusherEngine pe = new PusherEngine(f); 
      pe.addVideoItem(new VideoItem(...)); 
      pe.processItems(); 
     } 
    } 
} 

問題

在哪個lib/project應該定義IFactory接口? 應該在哪個lib/project中定義TranscoderFactory?

他們住在Transcoder庫中嗎?在PusherLib中?或者在實際的前端應用程序中? 我正在尋找最佳做法。

謝謝!

+0

+1的結構良好和書面問題... – 2012-04-25 16:30:03

+0

也許我錯過了點,或例如已經被過度簡化,但爲什麼你會需要一個工廠,如果你並不需要在運行時決定什麼實例化?你可以注入ITranscoder。 – 2012-04-26 08:08:23

+0

@filpen引擎需要爲每個項目實例化一個新的ITranscoder。如果沒有工廠就有辦法做到這一點,那麼在這種特殊情況下,這很可能是一種解決方案。 – luddet 2012-04-26 11:47:21

回答

1

在我看來,沒關係。對我來說,依賴注入的主要觀點是在測試時能夠注入除實際實現之外的東西。我將我的單元測試保存在一個單獨的項目中,以及用於測試的各種模擬定義。真正的實現以及「抽象」邏輯都保存在同一個程序集/項目/名稱空間中。

1

如果您確實需要工廠(請參閱評論),那麼Mark Seemann的this blog post解決了此問題。

簡而言之,如果您在工廠中使用IoC容器,則希望在組合根中使用它。如果不是這樣,它就不會像它正在實例化的類那樣留在同一個程序集中。

編輯

爲您的特定情況下,你不需要一個工廠,因爲你已經擁有你需要解決這種依賴性的一切。

using SimpleFFmpeg; 
namespace PusherLib { 
    public class PusherEngine { 
     private readonly ITranscoder _transcoder; 
     private readonly List<VideoItem> _items; 

     public PusherEngine(ITranscoder transcoder) { 
      _items = new List<VideoItem>(); 
      _transcoder = transcoder; 
     } 

     // ... 

     public void processItems() { 
      foreach (VideoItem item in _items) { 
       _transcoder.Transcode(item.FileName); 
      } 
     } 

     // ... 
    } 
} 

則初始化是這樣的:

namespace Pusher { 
    class Program { 
     static void Main(string[] args) { 
      ITranscoder t = new Transcoder(); 
      PusherEngine pe = new PusherEngine(t); 
      pe.addVideoItem(new VideoItem(...)); 
      pe.processItems(); 
     } 
    } 
} 

爲什麼需要你鏈接的答案工廠的理由是,只有在運行時已知的依賴需要的值,以便能夠被實例化,而你的依賴不需要創建運行時相關的參數。

+0

我將需要創建代碼轉換器的新實例,因爲我打算使處理多線程。 (一整套令人頭痛的問題:))所以我確實相信一個工廠是要走的路。無論如何,這是原則所追求的。 您提供給Mark Seemanns博客的鏈接非常有幫助!謝謝! – luddet 2012-04-26 13:16:28

+0

我沒有足夠的「聲譽」來標記你的答案是有用的,否則我會有。 – luddet 2012-04-26 13:24:59

0

爲了回答您的實際問題,而不是如果這是一個很好的用例工廠或不:

爲此我有時分裂InterfaceImplementation到不同的項目,像你IFactory的<>將住在Common.I項目中。 這在任何情況下都不起作用,但這種方法對我來說的一個優點是,我可以在有潛在技術更改的情況下將Implementation dll替換爲mocks或新的實現。
例如,我們最近從解析目錄中的xml文件切換到從服務獲取數據。我必須在客戶端機器上更新的唯一東西是這一個Implementation dll,因爲界面根本沒有改變。

但我想最後它並不重要,如前所述。