Ale*_*ruC 8 c# design-patterns
我有一个队列来处理while循环中的对象.它们在某处异步添加..像这样:
myqueue.pushback(String value);
Run Code Online (Sandbox Code Playgroud)
它们的处理方式如下:
while(true)
{
String path = queue.pop();
if(process(path))
{
Console.WriteLine("Good!");
}
else
{
queue.pushback(path);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,问题是我想修改它以支持类似TTL(生存时间)标志,因此文件路径将被添加超过n次.
我怎么能这样做,同时保留bool process(String path)
功能签名?我不想修改它.
我考虑过持有一个地图,或者一个列表,该列表计算进程函数为路径返回false的次数,并在第n次返回false时从列表中删除路径.我想知道如何更加动态地完成这项工作,并且我希望TTL能够在每次添加新流程时自动减少.我希望我不是在说垃圾.也许使用这样的东西
class JobData
{
public string path;
public short ttl;
public static implicit operator String(JobData jobData) {jobData.ttl--; return jobData.path;}
}
Run Code Online (Sandbox Code Playgroud)
我喜欢 JobData 类的想法,但已经有一个答案证明了这一点,并且您正在使用文件路径这一事实给您带来了另一个可能的优势。某些字符在文件路径中无效,因此您可以选择一个字符用作分隔符。这里的优点是队列类型仍然是字符串,因此您不必修改任何现有的异步代码。您可以在此处查看保留路径字符的列表:
http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
出于我们的目的,我将使用百分号 (%) 字符。然后你可以按如下方式修改你的代码,其他什么都不需要改变:
const int startingTTL = 100;
const string delimiter = "%";
while(true)
{
String[] path = queue.pop().Split(delimiter.ToCharArray());
int ttl = path.Length > 1?--int.Parse(path[1]):startingTTL;
if(process(path[0]))
{
Console.WriteLine("Good!");
}
else if (ttl > 0)
{
queue.pushback(string.Format("{0}{1}{2}", path[0], delimiter,ttl));
}
else
{
Console.WriteLine("TTL expired for path: {0}" path[0]);
}
}
Run Code Online (Sandbox Code Playgroud)
同样,从纯粹的架构角度来看,具有两个属性的类是更好的设计......但从实际的角度来看,YAGNI:此选项意味着您可以避免返回并更改推入队列的其他异步代码。该代码仍然只需要了解字符串,并且可以在未修改的情况下使用它。
还有一件事。我想指出的是,这是一个相当紧密的循环,很容易导致 CPU 核心失控。此外,如果这是 .Net 队列类型,并且您的紧密循环领先于异步生成以清空队列,您将抛出异常,这将打破 while(true) 块。您可以使用如下代码解决这两个问题:
while(true)
{
try
{
String[] path = queue.pop().Split(delimiter.ToCharArray());
int ttl = path.Length > 1?--int.Parse(path[1]):startingTTL;
if(process(path[0]))
{
Console.WriteLine("Good!");
}
else if (ttl > 0)
{
queue.pushback(string.Format("{0}{1}{2}", path[0], delimiter,ttl));
}
else
{
Console.WriteLine("TTL expired for path: {0}" path[0]);
}
}
catch(InvalidOperationException ex)
{
//Queue.Dequeue throws InvalidOperation if the queue is empty... sleep for a bit before trying again
Thread.Sleep(100);
}
}
Run Code Online (Sandbox Code Playgroud)