Phương thức tạo tĩnh - ưu và nhược điểm so với các hàm tạo


11

Những ưu và nhược điểm của việc có các phương thức tạo đối tượng tĩnh so với các hàm tạo là gì?

class Foo {
  private Foo(object arg) { }

  public static Foo Create(object arg) {
    if (!ValidateParam(arg)) { return null; }
    return new Foo(arg);
  }
}

Vài điều mà tôi có thể nghĩ đến:

Ưu điểm:

  • Trả về null thay vì ném một ngoại lệ (đặt tên cho nó TryCreate). Điều này có thể làm cho mã ngắn gọn hơn và sạch hơn về phía khách hàng. Khách hàng hiếm khi mong đợi một nhà xây dựng thất bại.
  • Tạo các loại đối tượng khác nhau với ngữ nghĩa rõ ràng, ví dụ CreatFromName(String name)CreateFromCsvLine(String csvLine)
  • Có thể trả về một đối tượng được lưu trữ nếu cần thiết hoặc thực hiện dẫn xuất.

Nhược điểm:

  • Ít khám phá hơn, khó đọc mã hơn.
  • Một số mẫu, như tuần tự hóa hoặc phản chiếu là khó khăn hơn (ví dụ Activator<Foo>.CreateInstance())

1
Nó chậm hơn. Bạn phải xử lý tham chiếu null nào.
Amir Rezaei

1
@Amir Xử lý null là ( Foo x = Foo.TryCreate(); if (x == null) { ... }). Xử lý một ngoại lệ ctor là ( Foo x; try { x = new Foo(); } catch (SomeException e) { ... }). Khi gọi một phương thức bình thường, tôi thích các ngoại lệ hơn cho các mã lỗi, nhưng với việc tạo đối tượng, TryCreatecó vẻ sạch hơn.
dbkk

Bạn có xác nhận sẽ thực hiện bất kỳ loại kiểm tra?
Amir Rezaei

Liên quan đến Pro thứ hai, "Tạo các loại đối tượng khác nhau với ngữ nghĩa rõ ràng, ví dụ CreatFromName (Tên chuỗi) và CreatFromCsvLine (Chuỗi csvLine)", bạn có thể tốt hơn để tạo Namevà nhập CsvLine, thay vì thể hiện các yêu cầu thông qua tên phương thức. Điều này sẽ cho phép bạn quá tải Tạo. Sử dụng chuỗi cho cả hai có thể được coi là "nỗi ám ảnh nguyên thủy" (giả sử bạn không đưa ra lựa chọn này vì lý do hiệu suất đã biết). Kiểm tra Object Calisthenics cho một cách thú vị để khám phá điều này.
bentayloruk

Câu trả lời:


7

Hạn chế lớn nhất với ' người tạo ' tĩnh có lẽ là hạn chế sự kế thừa. Nếu bạn hoặc người dùng thư viện của bạn lấy được một lớp từ bạn Foo, thì Foo::Create()sẽ trở nên vô dụng. Tất cả logic được xác định ở đó sẽ phải được viết lại một lần nữa trong kế thừa Create().

Tôi muốn đề xuất một thỏa hiệp: định nghĩa một hàm tạo với logic khởi tạo đối tượng tầm thường không bao giờ thất bại / ném, sau đó xác định (các) trình tạo với bộ đệm, xây dựng thay thế, v.v. .


1
Trong thực tế, nó không thực sự là một vấn đề, bởi vì hầu hết các lớp không được thiết kế để được kế thừa từ (và do đó nên được niêm phong / cuối cùng). Nếu sau này hóa ra bạn muốn mở lớp lên kế thừa, bạn luôn có thể di chuyển bất kỳ logic khởi tạo nào sang một hàm tạo được bảo vệ.
Doval

7

Tạo là một phương thức Factory. Khi tôi cảm thấy cần điều này, tôi triển khai mẫu Factory và định nghĩa một giao diện để thể hiện hợp đồng tạo đối tượng cũng như một lớp triển khai, sau đó được đưa vào khi cần thiết. Điều này vẫn giữ được những lợi thế của việc chuyển trách nhiệm sáng tạo ra khỏi lớp, nhưng tránh (hoặc ít nhất là làm rõ hơn) những hạn chế của việc thực hiện tạo đối tượng bên ngoài hàm tạo của lớp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.