0

C#. 私はと呼ばれる基本クラスを持っていますFileProcessor:

class FileProcessor {
    public Path {get {return m_sPath;}}

    public FileProcessor(string path) 
    {
        m_sPath = path;
    }

    public virtual Process() {}

    protected string m_sath;
}

今、私は他のクラスに作成したいと思いますExcelProcessor& PDFProcessor:

class Excelprocessor: FileProcessor 
{
    public void ProcessFile()
    {
        //do different stuff from PDFProcessor
    }
}

PDFProcessorの場合も同様で、Path が「.xlsx」で終わるファイルは Excel、「.pdf」で終わるファイルは pdf です。私はProcessingManagerクラスを持つことができます:

class ProcessingManager
{
    public void AddProcessJob(string path)
    {
        m_list.Add(Path;)
    }

    public ProcessingManager()
    {
        m_list = new BlockingQueue();
        m_thread = new Thread(ThreadFunc);
        m_thread.Start(this);
    }

    public static void ThreadFunc(var param) //this is a thread func
    {
        ProcessingManager _this = (ProcessingManager )var;
        while(some_condition) {
            string fPath= _this.m_list.Dequeue();
            if(fPath.EndsWith(".pdf")) {
                new PDFProcessor().Process();
            }
            if(fPath.EndsWith(".xlsx")) {
                new ExcelProcessor().Process();
            }
        }
    }

    protected BlockingQueue m_list;
    protected Thread m_thread;
}

これを可能な限りモジュール化しようとしています。たとえば、「.doc」処理を追加したいとします。マネージャー内でチェックを行い、別の を実装する必要がありますDOCProcessor。を変更せずにこれを行うにはどうすればよいProcessingManagerですか? 私のマネージャーが十分に大丈夫かどうか本当にわかりません。これに関するすべての提案を教えてください。

4

5 に答える 5

3

私はあなたの問題を本当に認識していませんが、試してみます。

Factory パターンを使用している可能性があります。

class FileProcessorFactory {
    public FileProcessor getFileProcessor(string extension){
        switch (extension){
            case ".pdf":
                return new PdfFileProcessor();
            case ".xls":
                return new ExcelFileProcessor();
        }
    }
}

class IFileProcessor{
    public Object processFile(Stream inputFile);
}

class PdfFileProcessor : IFileProcessor {
    public Object processFile(Stream inputFile){
        // do things with your inputFile
    }
}

class ExcelFileProcessor : IFileProcessor {
    public Object processFile(Stream inputFile){
        // do things with your inputFile
    }
}

これにより、FileProcessorFactory を使用して正しいプロセッサを取得していることを確認できます。IFileProcessor は、プロセッサごとに異なるものを実装していないことを確認します。

別の DOCProcessor を実装する

に新しいケースを追加し、 と呼ばれるFileProcessorFactoryインターフェースを実装する新しいクラスを追加するだけです。IFileProcessorDocFileProcessor

于 2013-06-10T15:54:17.890 に答える
2

次のようなカスタム属性でプロセッサを装飾できます。

[FileProcessorExtension(".doc")]
public class DocProcessor()
{

}

次に、処理マネージャーは、 FileProcessorExtension プロパティが拡張機能と一致するプロセッサを見つけ、それを再帰的にインスタンス化できます。

于 2013-06-10T15:50:20.063 に答える
1

CanHandleたとえば、次のメソッドをもう 1 つ使用します。

abstract class FileProcessor 
{
    public FileProcessor() 
    {
    }

    public abstract Process(string path);
    public abstract bool CanHandle(string path);
}

Excelファイルを使用すると、次のように実装できCanHandleます。

class Excelprocessor: FileProcessor 
{
    public override void Process(string path)
    {
    }

    public override bool CanHandle(string path)
    {
        return path.EndsWith(".xlsx");
    }
}

ではProcessingManager、実行時にメソッドによって追加できるプロセッサのリストが必要ですRegisterProcessor

class ProcessingManager
{
    private List<FileProcessor> _processors;

    public void RegisterProcessor(FileProcessor processor)
    {
        _processors.Add(processor)
    }
    ....

したがって、ここで LINQ を使用して適切なプロセッサを見つけることができます。

while(some_condition) 
{
     string fPath= _this.m_list.Dequeue();

     var proccessor = _processors.SingleOrDefault(p => p.CanHandle(fPath));
     if (proccessor != null)
         proccessor.Process(proccessor);
}

さらにプロセッサを追加する場合は、メソッドProcessingManagerを使用し て定義して追加するだけです。@Highmastdonの回答のようにRegisterProcessor、他のクラスのコードも変更しません。FileProcessorFactory

于 2013-06-10T16:09:04.210 に答える
1

Factoryパターンを使用できます(良い選択です)

  1. Factory パターンでは、既存のコードを変更しない可能性があります (SOLID 原則に従います)。
  2. 将来、新しい Doc ファイルのサポートが追加される場合は、辞書の概念を使用できます。(switch ステートメントを変更する代わりに)

    //Some Abstract Code to get you started (Its 2 am... not a good time to give a working code)
     1. Define a new dictionary with {FileType, IFileProcessor)
     2. Add to the dictionary the available classes.
     3. Tomorrow if you come across a new requirement simply do this.
         Dictionary.Add(FileType.Docx, new DocFileProcessor());
     4. Tryparse an enum for a userinput value. 
     5. Get the enum instance and then get that object that does your work!
    

それ以外のオプション: MEF (Managed Extensibility Framework!) を使用することをお勧めします。

そうすれば、クラスを動的に検出できます。

たとえば、.doc のサポートを実装する必要がある場合は、次のようなものを使用できます。

Export[typeof(IFileProcessor)]
class DocFileProcessor : IFileProcessor
{
    DocFileProcessor(FileType type);

    /// Implement the functionality if Document type is .docx in processFile() here
}

この方法の利点:

  1. IFileProcessor を実装しているため、DocFileProcessor クラスは自動的に識別されます。
  2. アプリケーションは常に拡張可能です。(すべてのパーツの importOnce を実行し、一致するパーツを取得して実行します。とても簡単です!)
于 2013-06-10T20:00:12.623 に答える
1

私はHighmastdonに同意します.彼の工場は良い解決策です. コアとなる考え方は、ProcessingManager に FileProcessor 実装の参照を持たず、IFileProcessor インターフェイスへの参照のみを持つことです。したがって、ProcessingManager は、処理するファイルの種類を認識せず、processFile(Stream inputFile) を実装する IFileProcessor であることを認識するだけです。 .

長期的には、新しい FileProcessor 実装を作成するだけで済みます。ProcessingManager は時間が経っても変化しません。

于 2013-06-10T16:12:47.953 に答える