2013-03-11 33 views
6

Gần đây tôi đã đọc rất nhiều về TDD và mã sạch nên tôi bắt đầu làm việc với một dự án đơn giản để sử dụng và tôi đã nghĩ ra điều gì đó mà tôi thực sự không biết cách tiếp cận tốt nhất là gì.Người gọi có nên kiểm tra tính hợp lệ của các đối số trước khi gọi hàm tạo không?

Tôi có một lớp có đối tượng Java File làm tham số, mong đợi là đối tượng File này phải là một thư mục và phải bắt đầu bằng một tiền tố nhất định. Lần đầu tiên tôi thực hiện việc kiểm tra đối tượng File trước khi gọi hàm tạo, nghĩa là kiểm tra xem đó có phải là thư mục và kiểm tra xem tên có hợp lệ không. Nhưng tôi không thích rằng đó là người gọi đó là xác định những gì làm cho nó hợp lệ và đặc biệt là những gì tiền tố hợp lệ là, tôi nghĩ rằng logic này nên được đặt trong lớp chính nó.

Tôi có thể thực hiện việc kiểm tra này trong hàm khởi tạo và ném ngoại lệ nếu nó không hợp lệ, nhưng do bản chất của vấn đề, nếu tôi lặp qua danh sách File s thì hoàn toàn mong đợi rằng một số người trong số họ đã thắng 't là' hợp lệ '(tức là chúng sẽ là các tập tin chứ không phải là thư mục) do đó, việc ném một số thực hiện bảo hành có thực sự là Exception không?

public MyObject(File directory) { 
    if (!directory.isDirectory()) { 
     throw new IllegalArgumentException("Must be a directory"); 
    } 
    if (!directory.getName().startsWith("Prefix")) { 
     throw new IllegalArgumentException("Must start with Prefix"); 
    } 
    .... 
} 

Tôi đã nghĩ về việc thêm phương thức Factory để tạo đối tượng và trả về null nếu File không hợp lệ.

public static MyObject createMyObject(File directory) { 
    if (!directory.isDirectory() || !directory.getName().startsWith("Prefix")) { 
     return null; 
    } 
    return new MyObject(directory); 
} 

Ngoài ra tôi nghĩ về việc thêm một phương pháp tĩnh để các lớp đó xác nhận File cho người gọi trước khi gọi các nhà xây dựng.

public static boolean isValid(File directory) { 
    return directory.isDirectory() && directory.getName().startsWith("Prefix"); 
} 

if (MyObject.isValid(directory)) { 
    MyObject object = new MyObject(directory); 
} 

Vì vậy, về mã sạch và tất cả nguyên tắc OOP (như trách nhiệm duy nhất, khớp nối, v.v.) sẽ là cách ưa thích để thực hiện việc này?

UPDATE:

Sau khi đọc một số câu trả lời đã được đăng lên đã Tôi bắt đầu suy nghĩ về một khả năng đó sẽ là chỉ áp dụng cho tình hình hiện tại của tôi chứ không phải quát như câu hỏi của tôi đã thực sự về.

Là một phần của mã gọi điện thoại, tôi có một đường dẫn từ hệ thống tệp và tôi liệt kê tất cả các tệp trong thư mục đó và đó là mỗi tệp mà tôi đang chuyển đến hàm tạo MyObject cho dù đó là hợp lệ hay không. Tôi có thể chuyển một FileFilter đến phương thức listFiles để đảm bảo rằng listFiles chỉ trả về các thư mục hợp lệ. Các FileFilter có thể được công bố trong vòng MyObject:

public static FileFilter getFilter() { 
    return new FileFilter() { 
     public boolean accept(File path) { 
      return path.isDirectory() && path.getName().startsWith("Prefix"); 
     } 
    }; 
} 

Nếu constructor của tôi đã ném một ngoại lệ sau đó nó thực sự sẽ là một trường hợp ngoại lệ vì kỳ vọng là nó chỉ được thông qua danh bạ hợp lệ. Làm điều này có nghĩa là tôi có thể loại bỏ sự cần thiết cho một ngoại lệ được kiểm tra từ nhà xây dựng/nhà máy vì bất kỳ ngoại lệ nào sẽ chỉ ra lỗi ở đâu đó thay vì hành vi mong đợi. Nhưng nó vẫn để lại câu hỏi liệu có nên đặt nó trong một nhà xây dựng hay một phương pháp nhà máy.

+0

Đối với tôi, thứ ba sẽ thích hợp hơn. Ngắn hơn và bạn có thể sử dụng nó với một số tệp. Ngoài ra, bạn không cần phải trả về một đối tượng mới từ phương thức isValid và bạn chỉ tạo đối tượng nếu isValid trả về true từ một phần khác của mã của bạn. Điều này là tốt vì nó tách các chức năng. –

+0

@AliAlamiri Trong điều khoản của mã sạch đó là sở thích của tôi bởi vì đọc nó làm cho ý nghĩa nhất, nghĩa là nó là rõ ràng cho người đọc những gì đang xảy ra.Tôi chỉ không thể quyết định nếu tôi thích thực tế là người gọi phải biết rằng anh ấy nên gọi isValid trước. – DaveJohnston

+0

Tại sao không truyền tệp cho hàm tạo và kiểm tra ở đó nếu tệp làValid. Điều này ẩn các kiểm tra từ người gọi khi bạn xây dựng các đối tượng và có các nhà xây dựng kiểm tra các tập tin được thông qua? –

Trả lời

1

Nó sẽ là sở thích của tôi để cung cấp sự kết hợp của một nhà xây dựng xác nhận và ném một ngoại lệ khi các đối số đưa ra không fullfill hợp đồng của nó bổ sung bằng phương pháp xác nhận static boolean isValid().

Được sử dụng trong vòng lặp, phương thức xác thực cung cấp một cách dễ đọc, dễ đọc để xây dựng các đối tượng hợp lệ, trong khi hàm tạo đảm bảo việc sử dụng không được xác thực được xử lý bằng cách ném một ngoại lệ khi cần.

3
public static MyObject createMyObject(File directory) throws IllegalArgumentException{ 
    if (!directory.isDirectory() || !directory.getName().startsWith("Prefix")) { 
     return throw new IllegalArgumentException("invalid parameters")"; 
    } 
    return new MyObject(directory); 
} 

Đây là một trong các tùy chọn kết hợp hai trong số các tùy chọn được đề xuất của bạn. Sử dụng phương pháp nhà máy và cũng xác nhận các điều kiện trước đó là những gì các phương pháp nhà máy đang làm tốt. Vì vậy, IMO này có thể là một lựa chọn tốt đẹp.

Tại sao không phương án 2 vì nó là: Bởi vì trở nulls là một lựa chọn tồi khi bạn có thể ném ngoại lệ để cảnh báo cho người dùng biết một số điều kiện tiên quyết không được đáp ứng.

UPDATE: Chiến lược này mang lại sự đảm bảo rằng chỉ có một đối tượng trong trạng thái hợp lệ sẽ được tạo ra. Ngoài ra, nếu bạn muốn giả lập trường hợp của MyObject, bạn có thể làm cho nó triển khai một số giao diện để sử dụng Đa hình thời gian chạy và vượt qua các đối tượng giả xung quanh. Hy vọng rằng có ý nghĩa.

+0

Trên một lưu ý riêng biệt cho TDD, đây là một nguồn tài nguyên tốt mà tôi đã sử dụng để hiểu các nguyên tắc cơ bản để viết mã có thể kiểm tra http://misko.hevery.com/code-reviewers-guide/ –

1

Tôi nghĩ mã xác nhận phụ thuộc vào chính xác những gì lớp 'MyObject' đại diện.

Nếu MyObject thực hiện một số thao tác thất bại nếu nó có tệp thay vì thư mục thì tôi sẽ nói nó nên chứa mã xác nhận trong hàm khởi tạo của nó - giúp lớp đó tự chứa và sẽ cho phép có thể sử dụng lớp sau.

Nếu MyObject chỉ là một vùng chứa cho tệp/thư mục và không có mã dành riêng cho thư mục, hãy đặt mã xác nhận bên trong lớp đó không yêu cầu thư mục thay vì tệp.

+0

Việc giữ mã xác nhận trong hàm tạo không được khuyến khích vì bạn bị mắc kẹt với hành vi này trong khi thử nghiệm và bạn chỉ muốn một mô hình được thông qua xung quanh, mà sẽ không thể ở đây. như khi bạn cố gắng tạo ra một mô hình với một số giá trị giả thì các giá trị giả đó PHẢI là hợp lệ để khởi tạo thành công. –

+0

Tôi nghĩ rằng việc kiểm tra các đối số bên trong một hàm tạo là khá chuẩn, Joshua Bloch chắc chắn khuyến khích nó mạnh mẽ trong Java hiệu quả: "Constructors thể hiện một trường hợp đặc biệt của nguyên tắc là bạn nên kiểm tra tính hợp lệ của các tham số được lưu trữ để sử dụng sau này. Điều quan trọng là kiểm tra tính hợp lệ của các tham số hàm tạo để ngăn chặn việc xây dựng một đối tượng vi phạm các bất biến lớp của nó. " – codebox

+0

Các nhà xây dựng nên chỉ chứa các nhiệm vụ và việc xác nhận trước điều kiện phải được thực hiện theo phương pháp nhà máy hoặc nhà máy cho đối tượng. http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/ đây là một tài nguyên tốt để quảng bá phương pháp này. –

0

Điều đó phụ thuộc ...

Từ góc độ mã hóa, cách tiếp cận đơn giản và sạch nhất là hàm tạo bùng nổ (unchdcked). Nếu có một kỳ vọng hợp lý mà người gọi sẽ và chỉ nên vượt qua các thư mục trong, sau đó đi với điều đó.

Nếu có một kỳ vọng hợp lý rằng người gọi có thể vượt qua trong phi thư mục, sau đó bạn có hai lựa chọn:

  1. Nếu người gọi có thể đối phó với tình hình, đã constructor ném một kiểm tra ngoại lệ
  2. Nếu người gọi không thể xử lý ngoại lệ, bạn có thể có lớp "không làm gì" nếu người gọi gọi phương thức - về cơ bản bỏ qua tất cả yêu cầu "làm" điều gì đó nếu Tệp được truyền tới hàm tạo không phải là thư mục.
+0

Vì vậy, ý tưởng được đưa ra một đường dẫn trong hệ thống tập tin mã sẽ lặp qua nội dung của nó và tạo ra một danh sách tất cả các thư mục với tiền tố đã cho. Vì vậy, nó là hoàn toàn hợp lý để mong đợi rằng một số nội dung sẽ không hợp lệ, vì vậy tôi sẽ không muốn các tập tin/thư mục được thêm vào danh sách. Tôi chỉ không chắc chắn về việc thêm ngoại lệ cho một nhà xây dựng hoặc cho dù nó là tốt hơn để đi với một nhà máy. – DaveJohnston

+0

Nhà máy hay không, bạn cần phải quyết định ai sẽ xử lý vấn đề. Một khi bạn tìm ra điều đó, cách tiếp cận nên rõ ràng. Lưu ý rằng một nhà máy không giúp đỡ trong trường hợp này - bạn vẫn còn lại với các lựa chọn tương tự, chỉ cần chuyển sang một phương pháp khác. Một nhà máy chỉ hữu ích nếu bạn cần phải làm điều gì đó với đối tượng sau khi nó được xây dựng (để tránh "cho phép' thoát này "khi' this' được chuyển đến một phương thức từ bên trong constructor). – Bohemian

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