2008-11-18 37 views
6

Hãy nói rằng chúng tôi cóConstructor tiêm và mặc định quá tải

public interface ITimestampProvider 
{ 
    DateTime GetTimestamp(); 
} 

và một lớp mà tiêu thụ nó

public class Timestamped 
{ 
    private ITimestampProvider _timestampProvider 

    public Timestamped(ITimestampProvider timestampProvider) 
    { 
     // arg null check 

     _timestampProvider = timestampProvider; 
    } 

    public DateTime Timestamp { get; private set; } 

    public void Stamp() 
    { 
     this.Timestamp = _timestampProvider.GetTimestamp(); 
    } 
} 

và thực hiện mặc định của:

public sealed class SystemTimestampProvider : ITimestampProvider 
{ 
    public DateTime GetTimestamp() 
    { 
     return DateTime.Now; 
    } 
} 

là nó hữu ích hoặc harfmful để giới thiệu nhà xây dựng này?

public Timestamped() : this(new SystemTimestampProvider()) 
{} 

Đây là câu hỏi chung, tức là dấu thời gian không phải là phần thú vị.

+0

Bạn có sử dụng CAB nào? Lâu đài? –

+0

Vì mục đích của câu hỏi này, không có câu hỏi nào. Đây là một yêu cầu chung về API. Tôi đã cập nhật câu hỏi để loại bỏ ý nghĩa "tiêm". –

Trả lời

7

Tôi nghĩ rằng nó phụ thuộc vào kịch bản, và về cơ bản là một chức năng của người tiêu dùng mã là (thư viện so với ứng dụng) và cho dù bạn đang sử dụng một container IoC hay không.

  • Nếu bạn đang sử dụng vùng chứa IoC, thì đây không phải là một phần của API công khai, cho phép thùng chứa nâng hạng nặng và chỉ có một hàm tạo duy nhất. Việc thêm hàm tạo no-args chỉ làm cho mọi thứ khó hiểu, vì bạn sẽ không bao giờ sử dụng nó.

  • Nếu đây là một phần của API công khai, hãy giữ cả hai. Nếu bạn đang sử dụng IoC, chỉ cần đảm bảo IoC của bạn tìm thấy hàm tạo "tham lam" (một đối số có nhiều đối số nhất). Folks không sử dụng IoC, nhưng sử dụng API của bạn sẽ đánh giá cao việc không phải xây dựng một biểu đồ toàn bộ phụ thuộc để sử dụng đối tượng của bạn.

  • Nếu bạn không sử dụng một thùng chứa IoC, nhưng chỉ muốn thử nghiệm đơn vị với một mô hình, hãy giữ hàm tạo không có arg và làm cho hàm tạo tham lam bên trong. Thêm InternalsVisibleTo cho assembly thử nghiệm đơn vị của bạn để nó có thể sử dụng hàm tạo tham lam. Nếu bạn chỉ là thử nghiệm đơn vị, thì bạn không cần thêm bề mặt API công khai.

+0

Đây sẽ là một phần của API công khai, vì vậy tôi đã chọn giữ nguyên tình trạng quá tải. Chỉ vì mặc định là hợp lý tôi thậm chí còn xem xét điều này. Tôi muốn các câu hỏi được trong một chân không IoC để tránh ảnh hưởng đến thiết kế cho một mối quan tâm hoàn toàn kỹ thuật. –

4

tôi sẽ không cung cấp hàm tạo đó. Làm như vậy làm cho nó quá dễ dàng để gọi TimeStamped mới và nhận một cá thể với SystemTimestampProvider() mới khi IoC của bạn có thể được cấu hình để sử dụng OtherTimestampProvider().

Cuối ngày, bạn sẽ kết thúc bằng một lần cố gắng gỡ lỗi tại sao bạn nhận được dấu thời gian sai.

Nếu bạn chỉ cung cấp hàm tạo đầu tiên, bạn có thể thực hiện tìm kiếm đơn giản của SystemTimestampProvider để tìm ra ai (sai) sử dụng nhà cung cấp đó thay vì nhà cung cấp cấu hình IoC.

+0

Mặc dù IoC không phải là một phần của kịch bản ở đây, tôi cho rằng hầu hết các triển khai sẽ bơm nhà cung cấp nếu được đăng ký, nếu không sử dụng hàm tạo mặc định, nghĩa là bạn sẽ chỉ nhận được 'SystemTimestampProvider' nếu bạn không ghi đè' ITimestampProvider'. ý định. Suy nghĩ? –

3

Nói chung tôi không nghĩ như vậy ... Nó phụ thuộc vào những gì bạn đang sử dụng Dependency Injection cho. Khi tôi sử dụng DI để kiểm tra đơn vị, tôi làm điều tương tự (nhiều hơn hoặc ít hơn) bằng cách khởi tạo phiên bản sản xuất của đối tượng phụ thuộc khi thể hiện được tiêm là rỗng ... Và sau đó tôi có quá tải không lấy tham số và đại biểu với một trong những hiện ... Tôi sử dụng một parameterless cho mã sản xuất, và tiêm một phiên bản thử nghiệm cho các phương pháp thử nghiệm đơn vị ...

Nếu bạn đang nói về một ứng dụng container IOC, otoh, bạn cần phải cẩn thận về can thiệp vào những gì các thiết lập cấu hình đang nói với các container để làm trong một cách đó là không rõ ràng ...

public class EventsLogic 
    { 
     private readonly IEventDAL ievtDal; 
     public IEventDAL IEventDAL { get { return ievtDal; } } 

     public EventsLogic(): this(null) {} 
     public EventsLogic(IIEEWSDAL wsDal, IEventDAL evtDal) 
     { 
      ievtDal = evtDal ?? new EventDAL(); 
     } 
    } 
0

tôi cố gắng tránh điều này - có một vài nơi tôi đã tìm thấy nó là một thiết kế hữu ích nhưng thường xuyên hơn t han tôi đã không tìm thấy nó chỉ dẫn đến tôi làm cho những sai lầm có thể là một chút khó hiểu để làm việc ra.

Sự cần thiết cho các đối tượng tiêm mặc định được giảm đáng kể bằng cách sử dụng thùng chứa phụ thuộc (tôi sử dụng StructureMap) để quản lý tất cả các dây này - thùng chứa DI đảm bảo rằng bạn luôn có được một ví dụ cụ thể mà bạn có thể sử dụng.

Nơi duy nhất tôi vẫn bị cám dỗ khi sử dụng hàm tạo mà bạn đề xuất trong các bài kiểm tra đơn vị nhưng gần đây tôi đã nhận được giá trị lớn hơn nhiều so với sử dụng các đối tượng giả hoặc giả.

Có những nơi có đối tượng phụ thuộc mặc định là thiết kế chính xác và hữu ích, nhưng nói chung tôi muốn nói rằng bạn chỉ giới thiệu khớp nối chặt chẽ không thêm nhiều giá trị.

0

Nó không hữu ích cũng không có hại. Nó đặt ra một vấn đề thẩm mỹ trong đó bạn đang hạn chế DI của bạn để tiêm constructor chỉ khi thiết kế của bạn có thể cho phép tiêm setter tài sản.

Một lựa chọn khác sẽ được thực hiện một getter mà trả về một thực hiện mặc định:

public DateTime Timestamp 
{ 
    get { return _timestampProvider??new SystemTimestampProvider(); } 
    set { _timestampProvider = value; } 
} 

Cách khác, bạn có thể thực hiện trên sử dụng một singleton nếu bạn đang lo lắng về việc tạo ra quá nhiều đối tượng trong heap.

0

Nhóm của tôi có rất nhiều thành công khi sử dụng phương pháp này. Tôi khuyên bạn nên thực hiện một thay đổi:
Chỉ đọc _timestampProvider. Điều này buộc các nhà cung cấp phải được xác định tại xây dựng và sẽ loại bỏ lỗi.

public class Timestamped 
{ 
    private readonly ITimestampProvider _timestampProvider; 

    public Timestamped(ITimestampProvider timestampProvider) 
    { 
     _timestampProvider = timestampProvider; 
    } 

    public Timestamped(): this(new SystemTimestampProvider()) 
    { } 
} 

Điều đó nói rằng, chúng tôi đang luôn nhìn vào công nghệ mới, bao gồm các khuôn khổ DI. Nếu chúng ta từ bỏ kỹ thuật này cho một cái gì đó tốt hơn đáng kể tôi sẽ cho bạn biết.

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