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
,我怎么能这样做?我真的不知道我的经理是否还行,请告诉我你对此的所有建议。
答案 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)
您可以使用工厂模式(一个不错的选择)
将来如果要添加新的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
}
此方法的优点: