2013-06-21 96 views
8

我有一个处理while循环中的对象的队列。他们是异步的地方加入..这样的:动态C#对象的设计模式

myqueue.pushback(String value); 

而且他们都是这样处理的:

while(true) 
{ 
    String path = queue.pop(); 
    if(process(path)) 
    { 
     Console.WriteLine("Good!"); 
    } 
    else 
    { 
     queue.pushback(path); 
    } 
} 

现在,事情是,我想修改该支持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;} 
} 
+1

你认为你的'JobData'方法有什么错误? –

+0

好的事情是我不想修改过程函数,我只想'JobData'对象能够在c#中对String进行隐式转换,并且有一些想法可以动态地并且隐含地减少tll值 – AlexandruC

+0

可能的附加我会提到但不认可的解决方案是使用TTL计数器向String类型添加扩展方法。不理想或不推荐,因为它增加了一个无意义的方法来处理字符串(甚至局限于本地命名空间),但它会解决您的具体问题。 –

回答

2

我喜欢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]); 
    } 
} 

再次,从一个纯粹的架构角度看,具有两个属性的类是更好的设计...但是从实际情况来看,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); 
    } 
} 
1

你可以抽象/封装的“作业管理器”的功能。隐藏来电者的队列和实施,这样你就可以做任何你想做的事情,而不需要来电者的照顾。类似这样的:

public static class JobManager 
{ 
    private static Queue<JobData> _queue; 

    static JobManager() { Task.Factory.StartNew(() => { StartProcessing(); }); } 

    public static void AddJob(string value) 
    { 
     //TODO: validate 

     _queue.Enqueue(new JobData(value)); 
    } 

    private static StartProcessing() 
    { 
     while (true) 
     { 
      if (_queue.Count > 0) 
      { 
       JobData data = _queue.Dequeue(); 
       if (!process(data.Path)) 
       { 
        data.TTL--; 
        if (data.TTL > 0) 
         _queue.Enqueue(data); 
       } 
      } 
      else 
      { 
       Thread.Sleep(1000); 
      } 
     } 
    } 

    private class JobData 
    { 
     public string Path { get; set; } 
     public short TTL { get; set; } 

     public JobData(string value) 
     { 
      this.Path = value; 
      this.TTL = DEFAULT_TTL; 
     } 
    } 

} 

然后你的处理循环可以处理TTL值。

编辑 - 添加了一个简单的处理循环。此代码不是线程安全的,但应该有希望给你一个想法。

+1

原始问题说:“我怎么能做到这一点,同时保持布尔过程(字符串路径)功能签名?”。我不知道我看到'process(String path)'适合你的代码...... – Chris

+1

这仍然在处理循环内 –

+1

像这样使用'Thread.Sleep()'是一个坏主意。有一个永远不会返回的'static'构造函数是一个非常糟糕的主意。 – svick

2

如果约束是bool process(String path)不能触及/更改然后把功能集成到myqueue。您可以保留其公共签名void pushback(string path)string pop(),但在内部您可以跟踪您的TTL。您可以将字符串路径包装到类似JobData的类中,该类可以添加到内部队列中,也可以按路径键入第二个Dictionary。也许甚至像保存最后的pop ed路径一样简单,并且如果后续push是相同的路径,则可以假定它是拒绝/失败的项目。另外,在你的pop方法中,你甚至可以丢弃一个已经被拒绝了太多时间的路径,并且在内部获取下一个路径,所以调用代码很幸福地不知道这个问题。

+0

鉴于推送代码的异步性质,将推送与最后一个流行音乐匹配似乎是一个非常糟糕的主意。 –

+0

是的,这是真的。可能最好坚持使用包装数据结构。 – tcarvin