C# 如何设计一个包含大量IF';s或Switch语句
如何使此类的设计更具动态性,以便根据需要添加新的扩展和类型C# 如何设计一个包含大量IF';s或Switch语句,c#,C#,如何使此类的设计更具动态性,以便根据需要添加新的扩展和类型 public class Processor { public Processor(string fileName) { string extension = Path.GetExtension(fileName); if(extension == "jpg" || extension == "gif" || extension == "png") {
public class Processor
{
public Processor(string fileName)
{
string extension = Path.GetExtension(fileName);
if(extension == "jpg" || extension == "gif" || extension == "png")
{
//Process Image file type
}
else if(extension == "xls" || extension == "xlsx")
{
//Process spreadsheet type
}
else if(extension == "doc" || extension == "docx")
{
//Process document file type
}
//and so forth ...
}
}
我们将来可能需要处理.tiff文件,或者我们可能需要处理视频文件,这意味着一个新的if分支
else if(extension == "avi" || extension == "mp4")
{
//Process video file type
}
正如你所见,这可能会持续很长时间
有效的文件类型和组存储在数据库中
有人能推荐一些模式或聪明的想法来解决这个问题吗?
干杯对于这个特殊的案例,我会构建如下内容
List<string> excelExtensions = new List<string>(){ "xls", "xlsx" };
List<string> wordExtensions = new List<string>(){ "doc", "docx" };
if(excelExtensions.Contains(extension))
{
}
if(wordExtensions.Contains(extension))
{
}
listextensions=newlist(){“xls”,“xlsx”};
List wordExtensions=newlist(){“doc”,“docx”};
if(excelExtensions.Contains(扩展))
{
}
if(wordExtensions.Contains(扩展名))
{
}
等等?使用字典
Dictionary<string, IFileHandler> fileHandlers = new Dictionary<string, IFileHandler>
{
{ "jpg", imageHander },
{ "gif", imageHander },
{ "xls", spreadsheetHander },
// ...
};
有效的文件类型和组存储在数据库中
然后,您可能希望查询数据库以从扩展名中获取正确的组,并将该组用作字典键而不是扩展名。一种方法可能是构建一个表(列表),其中每个项都包含扩展名以及有关如何使用该扩展名的信息 然后可以编写一个简单的循环,与表中的每个扩展进行比较
如果您对每个扩展所做的工作很复杂,并且无法在简单的表中定义,那么您可以改为包含一个委托。当循环找到匹配的扩展名时,它可以调用相应的委托来处理该名称。如果出于您陈述的原因(主要是必须返回并添加代码分支),这种结构通常是一件坏事 我将把它实现为一个字典,键入文件扩展名字符串,并包含方法委托作为值。如果设计得当,这将允许您在不影响旧代码的情况下添加新的扩展,因为新代码将位于一个完全不同的方法中,甚至可以位于具有此逻辑的类之外。然后,只需通过文件扩展名查找要调用的适当委托 基本示例:
//Put this in your class somewhere
public readonly Dictionary<string, Action<FileInfo>> fileHandlers = new Dictionary<string, Action<FileInfo>>();
...
//depending on the dictionary's visibility, you can add these from pretty much anywhere
fileHandlers.Add("xls", ProcessExcelFile);
fileHandlers.Add("xlsx", ProcessExcelFile);
fileHandlers.Add("jpg", ProcessImageFile);
...
//Then all you have to do to invoke the logic is...
fileHandlers[extension](fileInfo);
//把它放在你的类中的某个地方
public readonly Dictionary fileHandlers=new Dictionary();
...
//根据字典的可见性,您几乎可以在任何地方添加这些内容
添加(“xls”,ProcessExcelFile);
添加(“xlsx”,ProcessExcelFile);
添加(“jpg”,ProcessImageFile);
...
//那么你所要做的就是调用逻辑。。。
fileHandlers[扩展](fileInfo);
我建议为您的各种文件处理器提供一个接口,以实现:
public interface IFileProcessor
{
void Process(string fileName);
IEnumerable<string> FileExtensions {get;}
}
公共接口IFileProcessor
{
作废进程(字符串文件名);
IEnumerable文件扩展名{get;}
}
然后使用工厂为特定文件名获取适当的处理器。像其他回答者一样,我建议您使用字典来保持处理器及其文件名的映射。本例使用反射来注册它在加载的程序集中找到的每个文件处理器。这非常适合您的扩展性需求,因为您所需要的只是一些加载的程序集拥有一个实现此接口的类,并且它将自动向工厂注册。但是,您可以使用任何系统来注册这些类型:
public class ProcessorFactory
{
static IDictionary<string, IFileProcessor> ProcessorsByExtension =
new Dictionary<string, IFileProcessor>();
static ProcessorFactory()
{
var processorTypes =
from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetTypes()
where typeof(IFileProcessor).IsAssignableFrom(t)
select t;
foreach(var t in processorTypes)
{
// Preferably use your DI framework to generate this.
var processor = (IFileProcessor)Activator.CreateInstance(t);
foreach(var ext in processor.FileExtensions)
{
if(ProcessorsByExtension.ContainsKey(ext))
{
throw new InvalidOperationException(
"Multiple processors are registered to extension " + ext);
}
ProcessorsByExtension[ext] = processor;
}
}
}
public IFileProcessor GetProcessorForFile(string fileName)
{
string extension = Path.GetExtension(fileName);
return ProcessorsByExtension[extension];
}
}
公共类处理器工厂
{
静态IDictionary ProcessorsByExtension=
新字典();
静态处理器工厂()
{
变量处理器类型=
从AppDomain.CurrentDomain.GetAssemblys()中的
从a.GetTypes()中的t开始
其中typeof(IFileProcessor).IsAssignableFrom(t)
选择t;
foreach(processorTypes中的var t)
{
//最好使用您的DI框架来生成这个。
var processor=(IFileProcessor)Activator.CreateInstance(t);
foreach(processor.FileExtensions中的var ext)
{
if(ProcessorsByExtension.ContainsKey(ext))
{
抛出新的InvalidOperationException(
“多处理器注册到扩展”+ext);
}
ProcessorsByExtension[ext]=处理器;
}
}
}
公共IFileProcessor GetProcessorForFile(字符串文件名)
{
字符串扩展名=Path.GetExtension(文件名);
返回处理器ByExtension[扩展];
}
}
文件处理器接口的典型实现可能如下所示:
public class ImageFileProcessor : IFileProcessor
{
public IEnumerable<string> FileExtensions
{
get {return new[]{"jpg", "gif", "png"};}
}
public void Process(string fileName)
{
// Process Image file type
}
}
公共类ImageFileProcessor:IFileProcessor
{
公共IEnumerable文件扩展名
{
获取{returnnew[]{“jpg”、“gif”、“png”};}
}
公共作废进程(字符串文件名)
{
//处理图像文件类型
}
}
这种方法使您的代码保持模块化和可扩展性,同时提供优异的性能,即使您有大量的文件处理器。这种重构有一条规则--
- 用多态性/策略替换条件。 if/switch的明显问题是,此类代码中很可能存在错误,并且很难维护或增强
public class Processor
{
private Dictionary<string,FileParserBase> _fileExtension2FileParser;
public Processor() {
_fileExtension2FileParser = new Dictionary<string, FileParserBase>();
AddParser(new DocExtensionWordParser());
AddParser(new DocXExtensionWordParser());
//..more,more
}
private void AddParser(FileParserBase fileParserBase) {
_fileExtension2FileParser.Add(fileParserBase.Extension, fileParserBase);
}
public void Process(string fileName)
{
string extension = Path.GetExtension(fileName);
FileParserBase fileParser;
if (_fileExtension2FileParser.TryGetValue(extension, out fileParser)) {
fileParser.Process(fileName);
}
}
}
public interface FileParserBase
{
string Extension { get; }
void Process(string filePath);
}
public abstract class WordParserBase : FileParserBase
{
private string _extension;
public WordParserBase(string extension)
{
_extension = extension;
}
public override void Process(string filePath)
{
//Do the processing for WORD Document
}
public override string Extension
{
get { return _extension; }
}
}
public class DocExtensionWordParser : WordParserBase
{
public DocExtensionWordParser():base("doc"){}
}
public class DocXExtensionWordParser : WordParserBase
{
public DocXExtensionWordParser() : base("docx") { }
}
公共类处理器
{
专用字典_fileExtension2FileParser;
公共处理器(){
_fileExtension2FileParser=新字典();
AddParser(新的DocExtensionWordParser());
AddParser(新的DocXExtensionWordParser());
//…更多,更多
}
私有void AddParser(FileParserBase FileParserBase){
_fileExtension2FileParser.Add(fileParserBase.Extension,fileParserBase);
}
公共作废进程(字符串文件名)
{
字符串扩展名=Path.GetExtension(文件名);
文件标准
public class Processor
{
private Dictionary<string,FileParserBase> _fileExtension2FileParser;
public Processor() {
_fileExtension2FileParser = new Dictionary<string, FileParserBase>();
AddParser(new DocExtensionWordParser());
AddParser(new DocXExtensionWordParser());
//..more,more
}
private void AddParser(FileParserBase fileParserBase) {
_fileExtension2FileParser.Add(fileParserBase.Extension, fileParserBase);
}
public void Process(string fileName)
{
string extension = Path.GetExtension(fileName);
FileParserBase fileParser;
if (_fileExtension2FileParser.TryGetValue(extension, out fileParser)) {
fileParser.Process(fileName);
}
}
}
public interface FileParserBase
{
string Extension { get; }
void Process(string filePath);
}
public abstract class WordParserBase : FileParserBase
{
private string _extension;
public WordParserBase(string extension)
{
_extension = extension;
}
public override void Process(string filePath)
{
//Do the processing for WORD Document
}
public override string Extension
{
get { return _extension; }
}
}
public class DocExtensionWordParser : WordParserBase
{
public DocExtensionWordParser():base("doc"){}
}
public class DocXExtensionWordParser : WordParserBase
{
public DocXExtensionWordParser() : base("docx") { }
}