Phương pháp tiêm phụ thuộc so với phương pháp tĩnh


21

Hôm nay tôi đã có một cuộc thảo luận thú vị với một nhà phát triển khác về cách tiếp cận một lớp với phương thức chấp nhận chuỗi và xuất chuỗi.

Hãy tưởng tượng một cái gì đó giống như sau đây hoàn toàn được tạo ra cho mục đích ví dụ

public string GetStringPart(string input)
{ 
   //Some input validation which is removed for clarity

   if(input.Length > 5)
        return input.Substring(0,1);

   if(input.Substring(0,1) == "B")
        return input.Substring(0,3);

   return string.empty;
}

Một hàm có một số logic dựa trên đầu vào chuỗi của nó được thêm vào dự án bằng DI và có DI Container. Bạn sẽ thêm lớp mới này với một giao diện và đưa nó vào nơi cần thiết, hoặc bạn sẽ biến nó thành một lớp tĩnh? Những ưu và nhược điểm của mỗi là gì? Tại sao bạn (hoặc không) muốn tạo ra thứ gì đó được sử dụng với hàm xây dựng thay vì chỉ truy cập khi được yêu cầu ở bất cứ đâu.


1
@Ewan Dành cho các phương thức trợ giúp không sử dụng để trừu tượng hóa. Ví dụ: Tệp tin Apache.
Walfrat

3
@Ewan: phương pháp tĩnh không có tác dụng phụ là loại phương pháp tốt nhất, bởi vì chúng đơn giản để hiểu và đơn giản để kiểm tra.
JacquesB

1
nhưng họ không thể kiểm tra đơn vị những thứ phụ thuộc vào họ
Ewan

3
@Ewan Eh, không hẳn vậy. Có phải Math.Max ​​() xấu vì nó là tĩnh không? Nếu bạn kiểm tra phương thức tĩnh của mình và nó đang hoạt động, bạn có thể sử dụng nó một cách an toàn trên các phương thức khác mà không gặp sự cố. Nếu một tĩnh không thành công, thử nghiệm của nó sẽ bắt được nó.
T. Sar - Tái lập Monica

1
nếu 'tĩnh' được đảm bảo không có tác dụng phụ, tôi có thể thấy đối số. Nhưng nó không.
Ewan

Câu trả lời:


25

Không có lý do tại sao điều này cần phải được tiêm. Đây chỉ là một chức năng, nó không có phụ thuộc, vì vậy chỉ cần gọi nó. Nó thậm chí có thể tĩnh nếu bạn muốn nó trông thuần khiết. Người ta có thể viết bài kiểm tra đơn vị chống lại điều này mà không gặp khó khăn. Nếu nó được sử dụng trong các lớp khác, bài kiểm tra đơn vị vẫn có thể được viết.

Không cần phải trừu tượng hóa các chức năng mà không phụ thuộc, đó là quá mức cần thiết.

Nếu điều này trở nên phức tạp hơn thì có thể chuyển giao diện vào hàm tạo hoặc phương thức được bảo hành. Nhưng, tôi sẽ không đi vào con đường đó trừ khi tôi có GetStringPartlogic phức tạp dựa trên vị trí, v.v.


2
Đây là câu trả lời chính xác! Để xấu câu trả lời sùng bái hàng hóa đã được chấp nhận.
JacquesB

3
rằng hàm không có phụ thuộc không phải là điểm. vấn đề là khi những thứ khác phụ thuộc vào chức năng và trở nên gắn kết chặt chẽ với nó
Ewan

2
Điều gì sẽ xảy ra nếu chức năng thay đổi trong 6 tháng và không thuần túy, nhưng nó đã được sử dụng ở nhiều nơi. Nó không thể mở rộng dưới dạng tĩnh và nó cũng không phải là thứ có thể tách rời khỏi việc tiêu thụ các bài kiểm tra đơn vị lớp. Nếu thậm chí có một cơ hội nhỏ để thay đổi, tôi sẽ đi tiêm. Điều đó nói rằng, tôi sẵn sàng lắng nghe những lập luận trái ngược, đó là điểm chính của bài đăng này. Nhược điểm của việc này được tiêm và tích cực của một tĩnh là gì?
James

1
Nói chung, mọi người thảo luận về tiêm phụ thuộc trên trang web này, không có nhu cầu tiêm phụ thuộc. Do đó sự thiên vị đối với sự phức tạp không cần thiết.
Frank Hileman

2
@James Nếu chức năng trở nên kém tinh khiết, bạn đang làm gì đó sai và chức năng có thể không được xác định rõ ngay từ đầu. Tính diện tích hình vuông không nên đột nhiên cần một cuộc gọi cơ sở dữ liệu hoặc triển khai cập nhật trực quan cho giao diện người dùng. Bạn có thể tưởng tượng một kịch bản trong đó phương pháp sắp xếp "Chuỗi con" đột nhiên không trong sạch không?
T. Sar - Tái lập Monica

12

Đây là lý do tại sao

class DOSClient {
    OrderParser orderParser;
    string orderCode;

    DOSClient(OrderParser orderParser, string ordercode) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
    }
    void DisplayOrderCode() {
        Console.Write( "Prefix: " + orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

class GUIClient {
    OrderParser orderParser;
    string orderCode;
    GUI gui;

    GUIClient(OrderParser orderParser, string ordercode, GUI gui) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
        this.gui = gui;
    }

    void DisplayOrderCode() {
        gui.Prefix( orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

 

class OrderParserUS : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 5)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "B")
            return input.Substring(0,3);

        return string.empty;
    }
}

class OrderParserEU : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 6)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "#")
            return input.Substring(0,3);

        return string.empty;
    }
}

Nếu bạn đã sử dụng một phương thức tĩnh, sẽ không có cách nào thay đổi hành vi GetStringPartmà không phá hủy hành vi cũ hoặc làm ô nhiễm nó bằng logic có điều kiện. Đúng là thống kê là những quả cầu xấu xa được ngụy trang nhưng thực tế là chúng vô hiệu hóa đa hình là lời phàn nàn chính của tôi về chúng. Các phương thức tĩnh không phải là lớp đầu tiên trong các ngôn ngữ OOP. Bằng cách cung cấp cho phương thức một đối tượng để sống, ngay cả một đối tượng không có trạng thái, chúng ta tạo ra phương thức di động. Hành vi của nó có thể được truyền xung quanh giống như giá trị của một biến.

Ở đây tôi đã tưởng tượng một hệ thống cần hành xử hơi khác khi được triển khai ở châu Âu sau đó khi được triển khai ở Mỹ. Thay vào đó, buộc một trong hai hệ thống chỉ chứa mã mà chúng ta cần, chúng ta có thể thay đổi hành vi bằng cách kiểm soát đối tượng phân tích cú pháp thứ tự nào được đưa vào máy khách. Điều này cho phép chúng tôi chứa sự lây lan của chi tiết khu vực. Nó cũng giúp bạn dễ dàng thêm OrderParserCanada mà không cần phải chạm vào các trình phân tích cú pháp hiện có.

Nếu điều đó không có nghĩa gì với bạn thì thực sự không có lý lẽ nào cho việc này.

BTW, GetStringPartlà một cái tên khủng khiếp.


* Co rúm theo kiểu mã ngoặc * Tôi đoán bạn là một lập trình viên Java đang cố viết mã C #? Làm cho một người biết tôi giả sử. :)
Neil

Câu hỏi không dành riêng cho một ngôn ngữ, nhiều hơn về thiết kế. Vấn đề của tôi với các phương thức tĩnh là chúng ngăn cách ly mã để thử nghiệm. Nhà phát triển Tôi đã nói chuyện nghĩ rằng tôi phụ thuộc quá nhiều vào DI và đôi khi các phương thức mở rộng / phương thức tĩnh có liên quan. Tôi nghĩ có thể trong những trường hợp hiếm hoi nhưng không phải là mục đích chung. Cuộc thảo luận đang diễn ra mà tôi cảm thấy là một cuộc thảo luận tốt hơn. Tôi cũng đồng ý với trường hợp của bạn cho đa hình.
James

Kiểm tra là một lý do nhưng có nhiều hơn. Tôi không muốn đổ lỗi cho việc thử nghiệm này nhiều vì nó chỉ bắt đầu mọi người chỉ trích thử nghiệm. Một thực tế đơn giản là các lập trình viên thủ tục không thích nó nếu bạn không lập trình theo thủ tục.
candied_orange

Bạn không thể nói đơn giản static getStringPartEU()sao? Ví dụ của bạn chỉ có ý nghĩa nếu có các phương pháp khác trong lớp đó cũng yêu cầu xử lý EU chuyên biệt và chúng phải được coi là một đơn vị duy nhất.
Robert Harvey

2
Bạn chắc chắn đang tranh luận ủng hộ sự phức tạp không cần thiết. Tất cả mọi thứ có thể có nhiều mã hơn được thêm vào nó. Những điều cần thay đổi, nên dễ sửa đổi, nhưng bạn không nên cố gắng dự đoán những gì cần thay đổi trong tương lai. Các trường tĩnh có thể giống hệt với các biến toàn cục, nhưng các phương thức tĩnh có thể là thuần túy, loại phương thức tốt nhất có thể.
Frank Hileman
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.