这似乎在我的代码中出现了很多,我想知道是否有某种方法可以删除switch语句,或者是否有更优雅的方式来执行此操作?
public class MetaData
{
public string AlbumArtist { get; set; }
public string AlbumTitle { get; set; }
public string Year { get; set; }
public string SongTitle { get; set; }
public static MetaData CreateMetaDataFrom(IEnumerable<TextFrame> textFrames)
{
var metaData = new MetaData();
foreach (var frame in textFrames)
{
switch (frame.Descriptor.ID)
{
case "TPE1":
metaData.AlbumArtist = frame.Content;
break;
case "TALB":
metaData.AlbumTitle = frame.Content;
break;
case "TIT2":
metaData.SongTitle = frame.Content;
break;
case "TYER":
metaData.Year = frame.Content;
break;
}
}
return metaData;
}
}
答案 0 :(得分:3)
这与面向对象的方法有关。摆脱if或case的常用方法是使用标准和效果的查找表。还有其他技术使用同样的想法,例如数据导向编程(http://en.wikipedia.org/wiki/Data-directed_programming)和调度表(http://en.wikipedia.org/wiki/Dispatch_table)。许多语言实现使用类型调度表来实现虚方法调用。
查找表可以是一个用lambda函数填充的哈希表,如下所示:
Dictionary<string, Func<MetaData, string, string>> lookup = new Dictionary<string, Func<MetaData, string, string>>();
lookup["TPE1"] = (m, v) => m.AlbumArtist = v;
lookup["TALB"] = (m, v) => m.AlbumTitle = v;
lookup["TIT2"] = (m, v) => m.SongTitle = v;
lookup["TYER"] = (m, v) => m.Year = v;
然后在循环中将metaData字段分配为:
lookup[frame.Descriptor.ID](metaData, frame.Content);
答案 1 :(得分:1)
您可能希望了解如何实施策略模式。 DimeCasts.Net有一个很棒的视频教程可能会有所帮助。
答案 2 :(得分:1)
我很想提出策略模式但你可能需要稍微改变一下。考虑在TextFrame类中编写一个方法,让我们称之为putContent(MetaData)。
然后创建TextFrame的子类,每个子类表示不同的Frame类型。每个子类都将覆盖putContent(元数据)方法并执行其适当的逻辑。
TPE1的伪码示例:
Metadata putContent(MetaData md){
md.AlbumArtist = Content;
return md;
}
您将MetaData代码更改为:
var metaData = new MetaData();
foreach (var frame in textFrames)
{
metaData = frame.putContent(metaData);
}
return metaData;
当然,要创建TextFrames,他们自己将需要一个工厂,所以这不是故事的结尾。
答案 3 :(得分:1)
看起来你知道手头的类型是什么(使用开关)所以为什么不只是根据需要检索值,而不用for开关。
示例是在使用哈希表时,您知道哪些字段可用,只需使用字段。
ig你不确定该字段是否可用,如果列表包含值,则简单的测试就足够了。
如果列表具有值,您甚至可以编写辅助函数来检查并返回值。
答案 4 :(得分:1)
从您的代码中我得出结论IEnumerable&lt; TextFrame&gt;一共有4名成员 所以你可以写(没试过,所以检查语法):
public static MetaData CreateMetaDataFrom(IEnumerable<TextFrame> textFrames)
{
return new MetaData()
{
metaData.AlbumArtist = textFrames.Where(frame => frame.Descriptor.ID = "TPE1").SingleOrDefault().Content,
metaData.AlbumTitle = textFrames.Where(frame => frame.Descriptor.ID = "TALB").SingleOrDefault().Content,
metaData.SongTitle = textFrames.Where(frame => frame.Descriptor.ID = "TIT2").SingleOrDefault().Content;
metaData.Year = textFrames.Where(frame => frame.Descriptor.ID = "TYER").SingleOrDefault().Content;
};
}
答案 5 :(得分:0)
你真正拥有的是一个四向制定者。这里的规范重构是“用显式方法替换参数”(Martin Fowler的重构的p285)。他给出的Java示例正在改变:
void setValue(String name, int value) {
if (name.equals("height")) {
_height = value;
return;
}
if (name.equals("width")) {
_width = value;
return;
}
}
为:
void setHeight(int arg) {
_height = arg;
}
void setWidth(int arg) {
_width = arg;
}
假设CreateMetaDataFrom()
的调用者知道它传入了什么,你可以跳过switch/case
并使用这些属性的实际setter。