需要一些设计模式建议

时间:2013-06-10 15:47:09

标签: c# oop design-patterns

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,我怎么能这样做?我真的不知道我的经理是否还行,请告诉我你对此的所有建议。

5 个答案:

答案 0 :(得分: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将确保您没有为每个处理器实现不同的东西。

并实施另一个DOCProcessor

只需向FileProcessorFactory添加一个新案例,并添加一个实现名为IFileProcessor的{​​{1}}接口的新类。

答案 1 :(得分:2)

您可以使用以下自定义属性修饰处理器:

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

}

然后您的处理经理可以找到其FileProcessorExtension属性与您的扩展名匹配的处理器,并反复实例化它。

答案 2 :(得分:1)

再使用一个名为CanHandle的方法:

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 RegisterProcessor方法。您也不会更改其他类中的任何代码,即使FileProcessorFactory,如@Highmastdon的回答。

答案 3 :(得分:1)

我同意Highmastdon,他的工厂是一个很好的解决方案。核心思想是不再在ProcessingManager中有任何FileProcessor实现引用,只是对IFileProcessor接口的引用,因此ProcessingManager不知道它处理哪种类型的文件,它只知道它是一个实现processFile的IFileProcessor(Stream inputFile)

从长远来看,你只需编写新的FileProcessor实现,瞧。 ProcessingManager不会随着时间的推移而改变。

答案 4 :(得分:1)

您可以使用工厂模式(一个不错的选择)

  1. 在工厂模式中,有可能不更改现有代码(遵循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!
    
  3. 否则一个选项:最好使用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. 您的DocFileProcessor类会自动识别,因为它实现了IFileProcessor
    2. 应用程序始终是可扩展的。 (你执行所有部件的importOnce,得到匹配的部件并执行..就这么简单!)