2013-06-21 15 views
8

Tôi có một hàng đợi xử lý các đối tượng trong một vòng lặp while. Chúng được thêm vào không đồng bộ ở đâu đó .. như thế này:Mẫu thiết kế cho đối tượng C# động

myqueue.pushback(String value); 

Và họ được xử lý như thế này:

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

Bây giờ, điều là tôi muốn sửa đổi này để hỗ trợ một TTL-like (thời gian để sống) cờ, do đó, đường dẫn tệp sẽ được thêm o nhiều hơn n lần.

Làm cách nào tôi có thể thực hiện việc này, đồng thời giữ chữ ký chức năng bool process(String path)? Tôi không muốn sửa đổi điều đó.

Tôi đã nghĩ về việc giữ một bản đồ hoặc danh sách đếm số lần hàm xử lý trả về false cho đường dẫn và thả đường dẫn từ danh sách ở lần trả về sai thứ n. Tôi tự hỏi làm thế nào điều này có thể được thực hiện tự động hơn, và tốt hơn là tôi muốn TTL tự động giảm số lượng tại mỗi bổ sung mới cho quá trình này. Tôi hy vọng tôi không nói rác. Có thể sử dụng một cái gì đó như thế này

class JobData 
{ 
    public string path; 
    public short ttl; 

    public static implicit operator String(JobData jobData) {jobData.ttl--; return jobData.path;} 
} 
+1

Bạn nghĩ gì về phương pháp 'JobData' của mình? –

+0

Điều quan trọng là tôi không muốn sửa đổi chức năng xử lý, tôi chỉ muốn đối tượng 'JobData' có thể thực hiện chuyển đổi ẩn thành String trong C# và một số ý tưởng về việc giảm giá trị tll một cách năng động và rõ ràng – AlexandruC

+0

giải pháp mà tôi sẽ đề cập đến nhưng không xác nhận là thêm một phương thức mở rộng cho loại Chuỗi với bộ đếm TTL của bạn. Không lý tưởng hoặc được đề nghị vì nó thêm một phương thức vô nghĩa vào chuỗi ở khắp mọi nơi (thậm chí giới hạn trong một không gian tên rất cục bộ), nhưng nó sẽ giải quyết vấn đề cụ thể của bạn. –

Trả lời

2

Tôi thích ý tưởng của một lớp JobData, nhưng đã có một câu trả lời chứng minh rằng, và thực tế là bạn đang làm việc với các đường dẫn tệp cung cấp cho bạn một lợi thế có thể khác. Một số ký tự không hợp lệ trong đường dẫn tệp và do đó bạn có thể chọn một ký tự để sử dụng làm dấu phân cách. Lợi thế ở đây là loại hàng đợi vẫn là một chuỗi và do đó bạn sẽ không phải sửa đổi bất kỳ mã không đồng bộ hiện có nào của mình. Bạn có thể thấy một danh sách các nhân vật reserved con đường ở đây:

http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words

Đối với mục đích của chúng tôi, tôi sẽ sử dụng phần trăm (%) nhân vật. Sau đó, bạn có thể sửa đổi mã của bạn như sau, và không có gì khác cần phải thay đổi:

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

Một lần nữa, từ một kiến ​​trúc quan điểm thuần túy, một lớp học với hai thuộc tính là một thiết kế tốt hơn ... nhưng từ một quan điểm thực tế, YAGNI : tùy chọn này có nghĩa là bạn có thể tránh quay lại và thay đổi mã không đồng bộ khác đẩy vào hàng đợi. Mã đó vẫn chỉ cần biết về các chuỗi, và sẽ làm việc với điều này chưa sửa đổi.

Một điều nữa. Tôi muốn chỉ ra rằng đây là một vòng lặp khá chặt chẽ, dễ bị chạy đi với lõi cpu. Ngoài ra, nếu đây là loại hàng đợi .Net và vòng lặp chặt chẽ của bạn được tạo ra không đồng bộ của bạn để trống hàng đợi, bạn sẽ ném một ngoại lệ, sẽ thoát ra khỏi khối (true).Bạn có thể giải quyết cả hai vấn đề với mã như thế này:

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

Bạn có thể tóm tắt/đóng gói chức năng của "người quản lý công việc". Ẩn hàng đợi và thực hiện từ người gọi để bạn có thể làm bất cứ điều gì bạn muốn mà không cần người chăm sóc. Một cái gì đó như thế này:

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; 
     } 
    } 

} 

Sau đó, vòng xử lý của bạn có thể xử lý giá trị TTL.

Chỉnh sửa - Đã thêm vòng lặp xử lý đơn giản. Mã này không phải là luồng an toàn, nhưng hy vọng sẽ cung cấp cho bạn một ý tưởng.

+1

Câu hỏi ban đầu nói "Làm thế nào tôi có thể làm điều này, trong khi vẫn giữ chữ ký của quá trình bool (String path)?". Tôi không chắc chắn tôi thấy nơi 'quá trình (đường dẫn String)' phù hợp với mã của bạn ... – Chris

+1

Điều đó vẫn còn trong vòng xử lý –

+1

Sử dụng 'Thread.Sleep()' như thế này là một ý tưởng tồi. Có một hàm tạo 'tĩnh' không bao giờ trả về là một ý tưởng cực kỳ tồi tệ. – svick

2

Nếu ràng buộc là bool process(String path) không thể chạm vào/thay đổi sau đó đặt các chức năng vào myqueue. Bạn có thể giữ các chữ ký công khai của số void pushback(string path)string pop(), nhưng nội bộ bạn có thể theo dõi TTL của mình. Bạn có thể quấn các đường dẫn chuỗi trong một lớp giống như JobData được thêm vào hàng đợi nội bộ hoặc bạn có thể có một đường dẫn thứ hai là Dictionary. Có lẽ ngay cả một cái gì đó đơn giản như tiết kiệm cuối cùng pop ed đường dẫn và nếu sau push là cùng một con đường bạn có thể giả định nó là một mục bị từ chối/thất bại. Ngoài ra, trong phương thức pop của bạn thậm chí bạn có thể loại bỏ một đường dẫn đã bị từ chối quá nhiều thời gian và tìm nạp nội bộ đường dẫn tiếp theo để mã gọi điện thoại không biết rõ về vấn đề này.

+0

Với tính chất không đồng bộ của mã đẩy, khớp với một cú nhấn với pop cuối cùng có vẻ như là một ý tưởng rất tồi. –

+0

Đúng vậy. Có lẽ tốt nhất để gắn bó với cấu trúc dữ liệu gói. – tcarvin