2008-11-06 21 views
8

Tôi đang triển khai một lớp để so sánh các cây thư mục (trong C#). Lúc đầu, tôi đã thực hiện so sánh thực tế trong hàm tạo của lớp. Như thế này:Được coi là thiết kế xấu để thực hiện các hoạt động lâu dài trong một nhà xây dựng?

DirectoryComparer c = new DirectoryComparer("C:\\Dir1", "C:\\Dir2"); 

Nhưng nó không cảm thấy "đúng" để thực hiện một thao tác dài có thể trong hàm tạo. Một cách khác là làm cho hàm tạo riêng tư và thêm một phương thức tĩnh như sau:

DirectoryComparer c = DirectoryComparer.Compare("C:\\Dir1", "C:\\Dir2"); 

Bạn nghĩ sao? Bạn có mong đợi một nhà xây dựng được "nhanh" không? Là ví dụ thứ hai tốt hơn hay là nó chỉ làm phức tạp việc sử dụng lớp học?

BTW:

Tôi sẽ không đánh dấu bất kỳ câu trả lời như được chấp nhận bởi vì tôi không nghĩ rằng có một câu trả lời đúng, chỉ là sở thích và thị hiếu.

Edit:

Chỉ cần làm rõ ví dụ của tôi một chút. Tôi không chỉ insterested nếu các thư mục khác nhau, tôi cũng quan tâm đến cách chúng khác nhau (mà các tập tin). Vì vậy, một giá trị trả về int đơn giản sẽ không đủ. Câu trả lời của cdragon76.myopenid.com thực sự là khá gần với những gì tôi muốn (+1 cho bạn).

+1

Nếu bạn không đánh dấu câu trả lời, có lẽ đây phải là một wiki cộng đồng? –

+0

Tôi đồng ý [10chọn] –

Trả lời

10

Tôi thích thứ hai.

Tôi hy vọng người xây dựng sẽ tiến hành lớp học. Phương pháp so sánh thực hiện những gì nó được thiết kế để làm.

3

Bạn không bao giờ nên làm bất cứ điều gì có thể thất bại trong một nhà xây dựng. Bạn không muốn tạo các đối tượng không hợp lệ. Mặc dù bạn có thể triển khai trạng thái "zombie" trong đó đối tượng không làm được gì nhiều, tốt hơn hết là thực hiện bất kỳ logic phức tạp nào trong các phương thức riêng biệt.

+0

Hoàn toàn không sao đối với một nhà xây dựng không thành công và ném một ngoại lệ. Có rất nhiều ví dụ về điều này trong khuôn khổ. Nó phải chắc chắn rằng nó không bị rò rỉ một tham chiếu đến chính nó trong quá trình khởi tạo, nhưng ngoài việc đó là tốt. Không phải là tôi thích các nhà thầu phức tạp, hãy nhớ bạn. –

+0

Tôi không nghĩ rằng chỉ vì nó là trong khuôn khổ nó là OK. Khuôn khổ là tuyệt vời, nhưng nó không phải là hoàn hảo. Đó là lời khuyên tuyệt vời để nói rằng bạn không bao giờ nên làm những điều có thể thất bại trong một nhà xây dựng. Nhưng có, các nhà xây dựng nên được phép ném ngoại lệ trong trường hợp dữ liệu không hợp lệ, IMHO. – James

2

Có, điển hình là một nhà xây dựng là một cái gì đó nhanh chóng, nó được thiết kế để chuẩn bị các đối tượng để sử dụng, không thực sự làm các hoạt động. Tôi thích tùy chọn thứ hai của bạn vì nó giữ cho nó hoạt động một dòng.

Bạn cũng có thể làm cho nó dễ dàng hơn một chút bằng cách cho phép hàm tạo vượt qua hai đường dẫn, sau đó có phương thức Compare() thực sự xử lý.

5

Tôi nghĩ một giao diện có thể là những gì bạn đang theo dõi. Tôi sẽ tạo ra một lớp để đại diện cho một thư mục, và có thực hiện giao diện DirectoryComparer. Giao diện đó sẽ bao gồm phương thức so sánh. Nếu C# đã có một giao diện Comparable, bạn cũng có thể thực hiện điều đó.

Trong mã, cuộc gọi của bạn sẽ là:

D1 = new Directory("C:\"); 
.. 
D1.compare(D2); 
1

Tôi thích ví dụ thứ hai vì nó giải thích những gì đang xảy ra chính xác khi bạn khởi tạo đối tượng. Thêm vào đó, tôi luôn sử dụng hàm khởi tạo để khởi tạo tất cả các thiết lập chung cho lớp.

12

Tôi nghĩ rằng sự kết hợp của cả hai là lựa chọn "đúng", như tôi mong đợi phương pháp So sánh sẽ trả lại kết quả so sánh chứ không phải chính so sánh.

DirectoryComparer c = new DirectoryComparer(); 

int equality = c.Compare("C:\\Dir1", "C:\\Dir2"); 

... và như Dana đề cập, có giao diện IComparer trong .Net phản ánh mẫu này.

Phương thức IComparer.Compare trả về một int vì việc sử dụng các lớp IComparer chủ yếu là phân loại. Các mô hình chung mặc dù phù hợp với vấn đề của câu hỏi ở chỗ:

  1. Constructor khởi một ví dụ với (tùy chọn) "cấu hình" thông số
  2. Hãy so sánh phương pháp mất hai "dữ liệu" thông số, so sánh chúng và trả về một "kết quả "

Bây giờ, kết quả có thể là một int, một bool, một bộ sưu tập khác biệt. Bất cứ điều gì phù hợp với nhu cầu.

1

Tôi nghĩ rằng đối với một Comparer mục đích chung, bạn có thể xây dựng chỉ muốn xác định các tập tin bạn đang so sánh và sau đó so sánh later- cách này bạn cũng có thể thực hiện logic mở rộng:

  • Hãy so sánh again- gì nếu thư mục thay đổi?
  • Thay đổi các tệp bạn đang so sánh bằng cách cập nhật thành viên.

Ngoài ra, bạn có thể muốn xem xét trong việc triển khai của bạn nhận thư từ hệ điều hành của bạn khi các tệp đã được thay đổi trong thư mục đích và tùy chọn thu thập lại.

Vấn đề là bạn đang áp đặt giới hạn bằng cách giả định rằng lớp này sẽ chỉ được sử dụng để so sánh một lần cho một trường hợp duy nhất của các tệp đó.

Vì vậy, tôi thích:

DirectoryComparer = new DirectoryComparer(&Dir1,&Dir2);

DirectoryComparer->Compare();

Hoặc

DirectoryComparer = new DirectoryComparer();

DirectoryComparer->Compare(&Dir1,&Dir2);

+0

Tôi đồng ý và bạn vẫn có thể có một dòng bằng cách nói Thư mục mới (a, b) .Compare() –

+0

@Don: Một đồng nghiệp cũ gọi đó là "cố gắng làm quá nhiều thứ gợi cảm trên một dòng". Nếu lỗi mới không thành công vì bất kỳ lý do nào bạn vừa gây ra một ngoại lệ có thể khó theo dõi. – tloach

0

Nếu bạn đang làm việc với C#, bạn có thể sử dụng phương pháp khuyến nông để tạo ra một phương pháp để so sánh 2 thư mục mà bạn sẽ đính kèm vào bản dựng trong DirectoryClass, do đó, nó sẽ trông giống như sau:

Directory dir1 = new Directory("C:\....."); 
Directory dir2 = new Directory("D:\....."); 

DirectoryCompare c = dir1.CompareTo(dir2); 

Điều này sẽ thực hiện rõ ràng hơn nhiều. Thông tin thêm về phương pháp mở rộng here.

0

Nếu thao tác có thể mất một khoảng thời gian không xác định, đó là thao tác bạn có thể muốn xuất thành một chuỗi khác (vì vậy chủ đề chính của bạn sẽ không chặn và có thể làm những việc khác, như hiển thị chỉ báo tiến trình quay thí dụ). Các ứng dụng khác có thể không muốn thực hiện điều này, chúng có thể muốn mọi thứ trong một chuỗi (ví dụ: những ứng dụng không có giao diện người dùng). Việc tạo đối tượng di chuyển đến một luồng riêng biệt là một IMHO hơi khó xử. Tôi muốn tạo đối tượng (nhanh) trong chuỗi hiện tại của tôi và sau đó chỉ để cho một phương thức chạy trong chuỗi khác và sau khi phương thức chạy xong, chuỗi khác có thể chết và tôi có thể lấy kết quả của phương thức này trong thread hiện tại bằng cách sử dụng phương thức khác của đối tượng trước khi đổ vật thể, vì tôi vui vì ngay khi tôi biết kết quả (hoặc giữ một bản sao nếu kết quả liên quan đến nhiều chi tiết hơn, tôi có thể phải tiêu thụ từng cái một).

3

Tôi đồng ý với ý kiến ​​chung về việc không thực hiện các hoạt động kéo dài bên trong nhà thầu.

Ngoài ra, trong khi về chủ đề thiết kế, tôi sẽ xem xét thay đổi ví dụ thứ 2 của bạn sao cho phương thức DirectoryComparer.Compare trả về một thứ khác ngoài đối tượng DirectoryComparer. (Có lẽ một lớp mới gọi là DirectoryDifferences hoặc DirectoryComparisonResult.) Một đối tượng thuộc loại DirectoryComparer giống như một đối tượng bạn sẽ sử dụng để so sánh các thư mục chứ không phải đối tượng đại diện cho sự khác biệt giữa một cặp thư mục. Sau đó, nếu bạn muốn xác định các cách so sánh các thư mục khác nhau (như bỏ qua dấu thời gian, thuộc tính chỉ đọc, thư mục trống, v.v.), bạn có thể thực hiện các thông số đó mà bạn chuyển đến hàm dựng lớp DirectoryComparer. Hoặc, nếu bạn luôn muốn DirectoryComparer có cùng quy tắc để so sánh các thư mục, bạn có thể chỉ cần tạo DirectoryComparer một lớp tĩnh.

Ví dụ:

DirectoryComparer comparer = new DirectoryComparer(
    DirectoryComparerOptions.IgnoreDirectoryAttributes 
); 
DirectoryComparerResult result = comparer.Compare("C:\\Dir1", "C:\\Dir2"); 
0

Nếu các đối số được chỉ sẽ được xử lý một lần sau đó tôi không nghĩ rằng họ thuộc về là một trong hai đối số nhà xây dựng hoặc nhà nước chẳng hạn.

Nếu tuy nhiên dịch vụ so sánh sẽ hỗ trợ một số thuật toán tạm ngưng hoặc bạn muốn thông báo cho người nghe khi trạng thái bình đẳng của hai thư mục thay đổi dựa trên sự kiện hệ thống tập tin hoặc điều gì đó tương tự. Sau đó, thư mục ther là một phần của trạng thái cá thể.

Trong cả hai trường hợp, hàm tạo không thực hiện bất kỳ tác vụ nào khác ngoài việc khởi tạo một cá thể. Trong trường hợp hai ở trên thuật toán được điều khiển bởi một máy khách, giống như một Iterator chẳng hạn, hoặc nó được điều khiển bởi thread nghe sự kiện.

Tôi thường cố gắng làm những việc như sau: Không giữ trạng thái trong trường hợp nếu nó có thể được chuyển làm đối số cho phương thức dịch vụ. Cố gắng thiết kế đối tượng với trạng thái bất biến. Xác định các thuộc tính, giống như các thuộc tính được sử dụng trong equals và hashcode nên allways là không thay đổi.

Khái niệm một hàm tạo là một hàm ánh xạ một đối tượng đối tượng cho đối tượng mà nó đại diện.

Theo định nghĩa trên Integer.valueOf (1) thực sự là một hàm tạo nhiều hơn số nguyên mới (1) vì Integer.valueOf (1) == Integer.valueOf (1). , Trong cả hai trường hợp, khái niệm này cũng có nghĩa là tất cả các đối số cosntructor, và chỉ đối số hàm tạo, nên xác định hành vi bằng của đối tượng.

0

Tôi chắc chắn sẽ làm việc thứ hai.

Hành động dài trong một hàm tạo là tốt nếu chúng thực sự xây dựng đối tượng để có thể sử dụng được.

Bây giờ một điều mà tôi thấy mọi người làm trong các nhà xây dựng là gọi các phương pháp ảo. Đây là BAD kể từ khi ai đó sử dụng bạn như một lớp cơ sở và ghi đè một trong những hàm đó, bạn sẽ gọi phiên bản của lớp cơ sở không phải là lớp dẫn xuất khi bạn vào được hàm tạo của mình.

0

Tôi không nghĩ rằng việc nói về các thuật ngữ trừu tượng như "dài" có liên quan đến quyết định nếu bạn đặt thứ gì đó trong một hàm tạo hay không.

Một hàm tạo là một cái gì đó nên được sử dụng để khởi tạo một đối tượng, một phương pháp nên được sử dụng để "làm điều gì đó", tức là có một hàm.

1

Tôi nghĩ rằng việc xây dựng một đối tượng hợp lệ sẽ mất nhiều thời gian khi cần thiết để xây dựng một đối tượng hợp lệ, nhưng người xây dựng phải làm như vậy. Trì hoãn tạo đối tượng rất xấu khi bạn kết thúc với các đối tượng có khả năng không hợp lệ. Vì vậy, bạn sẽ phải kiểm tra một đối tượng mọi lúc trước khi bạn chạm vào nó (đây là cách nó được thực hiện trong MFC, bạn có bool IsValid() phương pháp ở khắp mọi nơi).

Tôi chỉ thấy sự khác biệt nhỏ trong hai cách tạo đối tượng. Người ta có thể thấy toán tử mới là hàm tĩnh của lớp. Vì vậy, điều này tất cả các nhọt xuống để cú pháp đường.

Lớp học DirectoryComparer làm gì? Trách nhiệm của nó là gì? Theo quan điểm của tôi (đó là chế độ xem của lập trình viên C++), có vẻ như bạn muốn sử dụng một chức năng miễn phí tốt hơn, nhưng tôi không nghĩ rằng bạn có thể có các chức năng miễn phí trong C#, đúng không? Tôi đoán bạn sẽ thu thập các tệp khác nhau trong đối tượng DirectoryComparer. Nếu vậy, bạn có thể tạo ra một thứ gì đó giống như một mảng các tệp hoặc một lớp tương đương được đặt tên tương ứng.

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