2016-11-30 35 views
8

Tôi không thoải mái về cách tôi đã thiết kế một chương trình đơn giản. Có một đối tượng FileParser có các sự kiện OnFileOpened, OnLineParsedOnFileClosed và một số đối tượng tạo tệp nhỏ hơn dựa trên nội dung của tệp mà các phân tích FileParser.Thành ngữ C# cho đối tượng chỉ tương tác mặc dù đã đăng ký các sự kiện

Các đối tượng quan sát FileParser đăng ký phương thức của họ với sự kiện FileParser trong các nhà thầu của họ.

ParsedFileFrobber(FileParser fileParser) 
{ 
    fileParser.OnFileOpen += this.OpenNewFrobFile; 
    fileParser.OnLineParsed += this.WriteFrobbedLine; 
    fileParser.OnFileClose += this.CloseFrobFile; 
} 

Sau đó, ParsedFileFrobber chỉ tiếp tục với những thứ không có tương tác rõ ràng hơn.

Điều làm phiền tôi là chương trình chính chỉ bao giờ gán một ParsedFileFrobber và về cơ bản không sử dụng giá trị trả về của hàm tạo, do đó, để nói.

var fileParser = new FileParser(myFilename); 
var parsedFileFrobber = new ParsedFileFrobber(fileParser); 
// No further mentions of parsedFileFrobber. 

Nó hoạt động, nhưng ReSharper phàn nàn về điều này, ít nhất khiến tôi tạm dừng suy nghĩ. Trên thực tế, tôi thậm chí không cần phải gán một biến cho kết quả của hàm khởi tạo, vì GC sẽ giữ cho số ParsedFileFrobber còn sống bằng các tham chiếu của trình xử lý sự kiện, nhưng một số new trống có vẻ rất sai với tôi. (Nó vẫn biên dịch và chạy đúng.)

var fileParser = new FileParser(myFilename); 
new ParsedFileFrobber(fileParser); 

Đây có phải là sự cố không? Nó có phải là một mẫu mã chống mùi hay không? Đã có một cách thành ngữ để làm điều này trong C#?

Cảm ơn!

Giải thích nhờ nhận xét hữu ích:

1) Tại sao không đảo ngược mối quan hệ? Cody Grey

Ah, ví dụ hơi quá đơn giản. Tôi thực sự có một số ParsedFileFrobber, một số ParsedFileGrobberParsedFileBrobber. Đảo ngược mối quan hệ sẽ làm cho các FileParser phụ thuộc vào tất cả 3. (Ngoài ra, ban đầu chỉ có một Frobber và một Grobber, nhưng sau đó có một nhu cầu cho một Brobber, và vẫn còn phạm vi cho uh, một Drobber và vv.) Tôi đoán rằng đó là vấn đề về việc liệu các dòng mã thực hiện đăng ký có xảy ra trong công cụ xây dựng FileParser hoặc trong các nhà thầu ParsedFileFrobber, ParsedFileGrobberParsedFileBrobber hay không, nhưng sở thích của tôi là cố gắng giữ cho số FileParser trở nên độc lập nhất có thể.

2) Tại sao không di chuyển hàm tạo thành một phương thức tĩnh (và làm cho hàm tạo riêng tư)? Hans Passant

Tôi có thể xem cách làm gọn đi việc sử dụng có thể không trực quan vào các hoạt động bên trong riêng tư của lớp học, đó là lời khuyên tốt. Tuy nhiên, nó vẫn sẽ là một trong các số new hoặc tham chiếu chỉ được gán cho giá trị trả về của hàm tạo. Vâng, nếu nó không phải là một vấn đề lớn, nó có ý nghĩa để ẩn đi các mã xấu xí. (Để tham khảo, tôi đã làm cho ParsedFileFrobber một số IDisposable với phương thức Dispose hủy đăng ký khỏi các sự kiện, vì vậy, có thể chấm dứt hoạt động.)

Cảm ơn tất cả các bình luận!

+2

Tôi không hoàn toàn chắc chắn rằng tôi hiểu thiết kế, nhưng câu hỏi đầu tiên của tôi sẽ là, tại sao không đảo ngược mối quan hệ? Hiện tại, bạn có ParsedFileFrobber phụ thuộc vào FileParser, nhưng sau đó không bao giờ sử dụng thể hiện của ParsedFileFrobber nữa. Tại sao không thay vì FileParser phụ thuộc vào ParsedFileFrobber, vì bạn (rõ ràng) vẫn giữ một tham chiếu đến đối tượng FileParser? –

+2

Không có nhiều điều để băn khoăn, chỉ là một lời nhắc nhở tốt rằng nó sẽ frob mãi mãi miễn là đối tượng FileParser vẫn còn sống. Bạn có thể làm cho nó trông "tự nhiên" bằng cách thêm một phương thức tĩnh vào ParseFileFrobber. Đặt tên nó là erm, Frob() hoặc Observe(). Đặt hàm tạo riêng tư. –

+0

Tôi tự hỏi tại sao bạn sẽ không cần tạo bản sao 'ParsedFileFrobber'. Rõ ràng là lớp (và người thân của nó 'ParsedFile *') đang làm điều gì đó trong các trình xử lý sự kiện tạo ra một trạng thái nhất định. Tiểu bang đó được giữ ở đâu? Từ những gì chúng ta biết, nó phải nằm trong 'ParsedFileFrobber'. Và nếu chúng ta quan tâm đến trạng thái đó (tôi đoán chúng ta đang có, nếu không, tại sao chúng ta sẽ phân tích tệp sau khi tất cả), chúng ta cũng cần phải truy cập cá thể của 'ParsedFileFrobber'. Dường như với tôi, chúng ta chỉ thấy một phần của bức tranh chứ không phải toàn bộ sự việc ở đây. –

Trả lời

0

Cuối cùng tôi đã đi với một cái gì đó giống như những gì Hans Passant đề nghị: làm sạch đi mới trần vào các hoạt động bên trong của một phương pháp tĩnh.

1

Một giải pháp có thể có thể là sử dụng Mediator pattern, giới thiệu một lớp mới kiểm soát tương tác giữa các lớp FileParserParsedFile* của bạn :. Bằng cách đó, các lớp học của bạn được kết hợp rất lỏng lẻo, FileParser của bạn không cần biết về số ParsedFileFrobber và ngược lại. Lớp hòa giải cũng có thể quan tâm đến tuổi thọ của vật thể.

public interface IParsedFile 
{ 
    void OnOpen(); 
    void OnLineParsed(string line); 
    void OnClosed(); 
} 

public class FileParseManager 
{ 
    private readonly FileParser _fileParser; 
    private readonly List<IParsedFile> _parsedFiles; 

    public FileParseManager(FileParser fileParser, List<IParsedFile> parsedFiles) 
    { 
     _fileParser = fileParser; 
     _parsedFiles = parsedFiles; 
    } 

    public void Parse(string fileName) 
    { 
     _fileParser.OpenFile(string fileName); 
     foreach (var parsedFile in _parsedFiles) 
     { 
      parsedFile.OnOpen(); 
     } 

     while ((string line = _fileParser.GetNextLine()) != null) 
     { 
      foreach (var parsedFile in _parsedFiles) 
      { 
       parsedFile.OnLineParsed(line); 
      } 
     } 

     _fileParser.CloseFile(); 
     foreach (var parsedFile in _parsedFiles) 
     { 
      parsedFile.OnClosed(); 
     } 
    } 
} 

Tùy chọn khác có thể là sử dụng mẫu sản xuất-người tiêu dùng. Một cái gì đó như thế này được cung cấp ví dụ: bởi TPL (Task Parallel Library) trong .NET Framework. Hãy xem Dataflow section và các ví dụ được cung cấp ở đó.

+0

Tôi đánh giá cao các tham chiếu, nhưng điều này dường như tái tạo hiệu ứng của hệ thống xử lý sự kiện một cách rõ ràng mà không có bất kỳ lợi thế rõ ràng nào, đặc biệt vì nó không cần thiết cho Grobber có OnOpen(), trong khi ở đây nó sẽ có được triển khai (như là một no-op). –

Các vấn đề liên quan