2013-06-10 5 views
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로 만들 싶습니다 경로로 끝나는 경우 PDFProcessor에 대한

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

같은, 파일은 엑셀 "입니다. xlsx "이고 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의 수정없이 어떻게해야합니까? 내 매니저가 충분히 괜찮은지 모르겠다. 내 의견을 말해 달라.

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

} 

이 그런 다음 처리 관리자가 누구 FileProcessorExtension 특성 확장 일치하는 프로세서를 찾을 수 있고, 반사적으로 인스턴스화 :

+1

[솔리드] (http://en.wikipedia.org/wiki/SOLID_ (object-oriented_design)) 디자인 패턴. – Brian

+0

단순한 디자인 패턴도 사용할 수 있지만 관리자에게 새 옵션을 추가해야합니다. –

+1

당신은 추상적 인 공장 디자인 패턴을보실 수 있습니다 http://www.oodesign.com/abstract-factory-pattern.html – terrybozzio

답변

3

나는 당신의 문제를 잘 알지 못한다. 그러나 나는 그것을 시도하려고 노력할 것이다.

공장 패턴을 사용할 수 있습니다.

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은 각 프로세서에 대해 여러 가지를 구현하지하고 있는지 확인합니다.

하고 그냥 FileProcessorFactory에 새 케이스를 추가 할 다른 DOCProcessor

을 구현하고 DocFileProcessor라는 인터페이스 IFileProcessor를 구현하는 새로운 클래스.

엑셀 파일로
abstract class FileProcessor 
{ 
    public FileProcessor() 
    { 
    } 

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

, 당신이 아래 CanHandle을 구현할 수 있습니다 :

+0

괜찮 았어.하지만 처리의 출력 경로를 나타내는 문자열이 있고 들어오는 모든 파일 유형에 공통적 인 문자열 인 경우 IFileProcessor 추상 클래스의 멤버 변수로 만들어야합니까? 그렇지 않으면 정적으로 가져와야합니까? .. 수업 ? 나는 항상 processorInstance.outputPath = 'xyz'를 설정하는 아이디어를 좋아하지 않습니다. – AlexandruC

+0

처리의 목적은 무엇입니까? 파일 시스템이나 데이터베이스에만 쓰기? 이를 위해'저장소 패턴 '을보고 싶을 수도있다. 호출 코드가 파일 시스템에 대한 쓰기를 담당하게 할 수 있습니다. 또는'IFileProcessor.processFile (Stream inputFile, FileInfo filePath);에 변수를 추가하십시오. – Highmastdon

+0

출력 경로에서 파일의 값을 추출하고 다른 파일에 씁니다. – AlexandruC

2

사용자 정의는 다음과 같은 속성을 사용하여 프로세서를 장식 할 수있다.

+0

좋은 속성 중 하나는 분명히 사용자 지정 속성에 대해 알지 못했습니다. 내 매니저가 뭘로 충분하니? – AlexandruC

1

를 사용하여 또 하나의 방법은 예를 들어 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); 
} 

당신이 더 많은 프로세서를 추가 단지 정의하고 RegisterProcessor 방법을 사용하여 ProcessingManager에 추가하려면

. FileProcessorFactory @ Highmastdon의 답변도 다른 클래스의 코드를 변경하지 마십시오.

+0

ProcessingManager를 시작하기 오래 전에 구성 파일에서 읽을 수있는 일반적인 출력 경로가 있는지 생각해보십시오 ? FileProcessor 클래스 안에 또 다른 _outputPath 멤버를 저장하는 것이 충분히 우아하다고 생각하지 않습니다. – AlexandruC

+0

@ A.K : 솔직히 말해서, 나는 당신의 의견을 많이 이해하지 못한다. 당신의 질문을 더 자세하게 업데이트 할 수 있겠는가? –

1

나는 Highmastdon에 동의합니다. 그의 공장은 좋은 해결책입니다. 핵심 개념은 ProcessingManager에서 FileProcessor 구현 참조를 더 이상 가지지 않고 IFileProcessor 인터페이스에 대한 참조 만 처리하는 것이므로 ProcessingManager는 처리 할 파일 유형을 알지 못합니다. 단지 processFile (Stream inputFile)을 구현하는 IFileProcessor라는 것을 알고 있습니다. .

장기적으로 새로운 FileProcessor 구현체를 작성해야합니다. ProcessingManager는 시간이 지나도 변하지 않습니다.

+0

내 솔루션에 대한 설명 주셔서 감사합니다 :) 독자들에게 더 명확하게 해줄 것입니다. – Highmastdon

1

당신은 기존 코드를 (SOLID 원칙에 따라) 변경하지 가능성이 공장 패턴에서 공장 패턴 (좋은 선택)

  1. 를 사용할 수 있습니다.
  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로 이동하는 것이 좋습니다

그런 식으로, 동적으로 클래스를 발견 할 수 있습니다. 예를 들어

.DOC에 대한 지원은 아래 같은 것을 사용할 수 있습니다 구현해야하는 경우이 방법의

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

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

장점 :

그것을 구현하는 당신의 DocFileProcessor 클래스가 자동으로 식별됩니다
  1. 이후 IFileProcessor
  2. 응용 프로그램은 항상 확장 가능합니다. (당신은 모든 부품을 importOnce하고, 일치하는 부품을 얻고 Execute .. 그 간단한!)
관련 문제