Việc sử dụng *** Helper hay *** Sử dụng các lớp chỉ chứa các phương thức tĩnh là AntiPotype


19

Tôi thường xuyên phải đối mặt với các lớp trợ giúp hoặc sử dụng trong Java hoặc bất kỳ loại ngôn ngữ nào. Vì vậy, tôi đã tự hỏi mình liệu đây có phải là một loại Anti Pattern nào đó không và sự tồn tại của các loại lớp này chỉ là thiếu sót trong thiết kế và kiến ​​trúc của Phần mềm.

Thông thường các lớp này được giới hạn bằng cách sử dụng chỉ các phương thức tĩnh, làm rất nhiều thứ. Nhưng chủ yếu là nó thực sự phụ thuộc vào bối cảnh và trạng thái.

Câu hỏi của tôi là, ý kiến ​​của bạn về loại lớp trợ giúp / sử dụng tĩnh như vậy là gì bởi vì lợi thế tất nhiên là việc gọi nhanh chỉ bằng tên lớp.

Và ở mức độ trừu tượng nào bạn sẽ tránh sử dụng các loại lớp này?

Theo tôi, từ khóa "tĩnh" chỉ nên được cho phép trong khai báo của một lớp (Java) chứ không phải cho các phương thức. Theo tôi là sử dụng nó theo cách này, nó có thể là một sự thay thế tốt và giữa chừng để có thể kết hợp Procuedural- và OO-Paradigms trong Java và tránh bỏ sót từ khóa.

Bổ sung do các câu trả lời:

Lúc đầu, tôi nghĩ rằng việc kết hợp các mô hình khác nhau và thậm chí sử dụng các ngôn ngữ kịch bản được diễn giải trong máy hoặc mã được biên dịch là hoàn toàn hợp pháp.

Kinh nghiệm của tôi là trong quá trình phát triển của một dự án, những người trợ giúp và tiện ích như vậy, bất kể tên là gì, đang phát triển và phát triển và được sử dụng trong mọi góc bị lãng quên của codebase, vốn được thiết kế theo dạng mô đun và flexibel. Và do không có thời gian để thực hiện tái cấu trúc hoặc nghĩ về thiết kế một lần nữa, bạn chỉ làm cho nó tồi tệ hơn theo thời gian.

Tôi nghĩ staticnên được loại bỏ khỏi Java. Đặc biệt là bây giờ nơi có thể sử dụng các yếu tố ngôn ngữ chức năng thậm chí tinh vi hơn.



Tôi nghĩ rằng nếu người trợ giúp không cần phải khởi tạo một lớp học, thì tốt thôi. Vấn đề là khi người trợ giúp khởi tạo một triển khai cụ thể của một lớp và sau đó bạn không thể chế giễu giao diện đó. Nếu người trợ giúp được thông qua một giao diện hoặc một lớp trừu tượng, tôi nghĩ rằng nó ổn.
bobek 18/07/18

Sẽ tốt thôi nếu bạn yêu cầu thực hiện lập trình thủ tục. Không phải là nếu bạn yêu cầu lập trình đối tượng (định hướng).
Phát hiện

1
@ Spiated: và vì không có giá trị kinh doanh khi tuyên bố bạn chỉ lập trình hướng đối tượng, chỉ luôn luôn lập trình mô hình hỗn hợp và hoàn thành công việc.
RemcoGerlich

@RemcoGerlich Chính xác. Quan điểm của tôi là lưu ý rằng câu trả lời chủ yếu là "triết học", liên quan đến mô hình lập trình mà bạn xem xét.
Phát hiện

Câu trả lời:


20

Chà, Java thiếu các hàm miễn phí, do đó bạn buộc phải đặt chúng dưới dạng các hàm tĩnh vào một số lớp pro-forma. Một công việc cần thiết không bao giờ là một mô hình chống, mặc dù nó có thể thiếu sự thanh lịch.

Tiếp theo, không có gì sai với các chức năng miễn phí. Trên thực tế, sử dụng các chức năng miễn phí làm giảm khớp nối, vì chúng chỉ có quyền truy cập vào giao diện công cộng thay vì tất cả các chi tiết chính.

Tất nhiên, sử dụng các hàm tự do / tĩnh không bằng bất kỳ cách nào làm giảm bớt sự nguy hiểm của trạng thái chia sẻ có thể thay đổi, đặc biệt là toàn cầu.


2
@TimothyTruckle Hoặc là tĩnh hoặc chúng có phần thừa thisvà yêu cầu một cái gì đó được khởi tạo một cách thích hợp
Caleth

6
@TimothyTruckle Vì đó là Java. Các ngôn ngữ khác có thể có các hàm miễn phí mà không cần phải đặt chúng vào một lớp chỉ để khai báo nó không phải là một phương thức cá thể. Và tại một số điểm, bạn phải có khớp nối chặt chẽ. Cho dù đó là tốt hay không là hoàn toàn tùy thuộc vào những gì các chức năng trong câu hỏi không .
nvoigt

5
@TimothyTruckle Tuyệt đối, duy trì trạng thái sẽ là lý do chính cho việc "không tốt".
nvoigt

2
@nvoigt, tôi cảm thấy câu trả lời này sẽ được cải thiện rất nhiều bằng cách nêu rõ điểm đó. Thống kê nhà nước là xấu; những người không quốc tịch là tốt. Thực sự khá đơn giản.
David Arno

3
@TimothyTruckle Đó không phải là khớp nối chặt chẽ. Bạn đang mô tả khớp nối lỏng lẻo. Khớp nối chặt chẽ trong bối cảnh này sẽ ngụ ý một số loại phụ thuộc lẫn nhau. Một phụ thuộc một chiều không đáp ứng yêu cầu đó.
JimmyJames

18

Tiện ích tĩnh hoặc các hàm trợ giúp không phải là một mẫu chống nếu chúng tuân thủ một số nguyên tắc:

  1. Họ sẽ không có tác dụng phụ

  2. Chúng được sử dụng cho hành vi cụ thể của ứng dụng không thuộc về lớp hoặc các lớp mà các hàm này hoạt động

  3. Họ không yêu cầu bất kỳ trạng thái chia sẻ

Các trường hợp sử dụng phổ biến:

  • Định dạng ngày theo cách cụ thể của ứng dụng
  • Các hàm lấy một loại làm đầu vào và trả về một loại khác.

Ví dụ, trong một ứng dụng tôi đã làm việc trên người dùng giữ các mục nhật ký cho các hoạt động của họ. Họ có thể chỉ định ngày theo dõi và tải xuống lời nhắc sự kiện. Chúng tôi đã tạo một lớp tiện ích tĩnh để lấy một mục nhật ký và trả về văn bản thô cho tệp .ics.

Nó không yêu cầu bất kỳ trạng thái chia sẻ. Nó không làm thay đổi bất kỳ trạng thái nào và việc tạo ra một sự kiện iCal chắc chắn là ứng dụng cụ thể và không thuộc về lớp nhập nhật ký.

Nếu các hàm tĩnh hoặc các lớp tiện ích có tác dụng phụ hoặc yêu cầu trạng thái chia sẻ, tôi sẽ khuyên bạn nên đánh giá lại mã này, vì nó giới thiệu khớp nối có thể khó giả định để thử nghiệm đơn vị.


4

Nó sẽ phụ thuộc vào cách tiếp cận của bạn. Nhiều ứng dụng được viết với nhiều chức năng hơn, trái ngược với suy nghĩ cổ điển (bao gồm phần lớn các trang web bạn đang truy cập).

Với lối suy nghĩ này, sẽ có nhiều phương thức tiện ích trên các lớp worker có thể được xâu chuỗi lại với nhau như các phương thức tĩnh. Chúng được cho ăn / sử dụng gần hơn với các đối tượng đơn giản chỉ chứa dữ liệu và được truyền xung quanh.

Đó là một cách tiếp cận hợp lệ và có thể hoạt động rất tốt, đặc biệt là ở quy mô.


"Có thể hoạt động rất tốt, đặc biệt là ở quy mô" Không. Nguyên nhân khớp nối chặt chẽ bởi truy cập tĩnh sẽ sớm cản trở bạn khi dự án phát triển.
Timothy Truckle

@TimothyTruckle Bạn có thể giải thích làm thế nào Agent.Save (obj) được liên kết chặt chẽ hơn nhiều so với obj.Save ()? Tác nhân có khả năng nhận được tham chiếu DI / IoC, ngay cả đối với các phương thức tĩnh như là một thể hiện của lớp aa. Để tham khảo Stack Exchange, bản thân nó được viết theo kiểu tư duy này và đã mở rộng tốt hơn bất kỳ ứng dụng ASP.Net nào khác có ít tài nguyên hơn bất kỳ ứng dụng nào tôi biết.
Tracker1

"Bạn có thể giải thích làm thế nào Agent.Save (obj) được liên kết chặt chẽ hơn nhiều so với obj.Save () không?" Đây là ví dụ sai. Một ví dụ đúng sẽ là Agent.Save(obj)vs agentInstance.Save(obj). Với cái sau bạn có khả năng tiêm agentInstance vào mã sử dụng. Hậu quả là bạn có thể tiêm bất kỳ lớp con của Agentquá cho phép tái sử dụng og mã sử dụng với "loại" khác nhau Agentmà không cần biên dịch lại. Đây là khớp nối thấp .
Timothy Truckle

Tôi nghĩ rằng nó thực sự đi xuống một vài điều. Là trạng thái cần thiết, nó cần linh hoạt đến mức nào, và có ổn không khi có trạng thái toàn cầu / thể hiện? Điều đó tùy thuộc vào từng nhà phát triển / kiến ​​trúc sư quyết định. Tôi thích một cơ sở mã đơn giản hơn là thêm độ phức tạp cho các tình huống khiến mọi thứ trở nên khó hiểu hơn. Một trong những điều tôi thích về nút / js là tôi có thể viết mã đơn giản / sạch và vẫn tiêm để kiểm tra mà không cần mã được ghi vào các chi tiết cụ thể của DI / IoC.
Tracker1

2

Cá nhân tôi nghĩ rằng phần quan trọng duy nhất về các lớp người trợ giúp như vậy là chúng được đặt ở chế độ riêng tư. Bên cạnh đó - chúng hoàn toàn là một ý tưởng tốt (áp dụng một cách tiết kiệm).

Cách tôi nghĩ về điều này - là nếu trong việc thực hiện một lớp (hoặc hàm) - một cái gì đó như thế này là hữu ích, và làm cho việc thực hiện đó rõ ràng hơn, làm thế nào điều đó có thể xấu? Và OFTEN rất quan trọng để xác định các lớp trình trợ giúp riêng như vậy để cho phép tích hợp và sử dụng các thuật toán khác phụ thuộc vào dữ liệu trong một hình dạng cụ thể.

Có nên gắn nhãn 'người trợ giúp' hay không là một vấn đề nhỏ của sở thích cá nhân, nhưng điều đó có nghĩa là nó giúp thực hiện và không quan tâm / sử dụng đến đối tượng rộng hơn. Nếu đó là những gì có ý nghĩa - đi cho nó!


1
Các lớp tiện ích công cộng vẫn có thể hữu ích. Ví dụ chính : java.lang.Math.
amon

1

Sự phổ biến của staticcác lớp người trợ giúp dựa trên một quan niệm sai lầm. Chỉ vì chúng tôi gọi các lớp chỉ có staticphương thức là "lớp tiện ích" không có nghĩa là nó không được phép viết hành vi phổ biến trong POJO.

static các lớp trợ giúp là mô hình chống vì ba lý do:

  1. Việc truy cập tĩnh vào các phương thức trợ giúp này ẩn các phụ thuộc . Nếu các "lớp tiện ích" này là POJO, bạn có thể đưa chúng int vào một lớp phụ thuộc làm tham số hàm tạo, điều này sẽ làm cho sự phụ thuộc rõ ràng đối với bất kỳ người dùng nào của lớp phụ thuộc.

  2. Việc truy cập tĩnh vào các phương thức trợ giúp này gây ra sự liên kết chặt chẽ . Điều này có nghĩa là mã sử dụng các phương thức của trình trợ giúp khó sử dụng lại và (như là một tác dụng phụ) để kiểm tra.

  3. Đặc biệt là nếu họ duy trì trạng thái, đây chỉ là các biến toàn cầu . Và hy vọng không ai tranh luận rằng các biến toàn cầu là tốt ...

Các lớp trình trợ giúp tĩnh là một phần của mẫu chống mã STUPID .


Trạng thái toàn cầu không liên quan đến câu hỏi, - max630

OP đã viết:

Nhưng chủ yếu là nó thực sự phụ thuộc vào bối cảnh và trạng thái.

Tĩnh statefull cấu trúc các quốc gia toàn cầu.

bất kỳ loại mã nào cũng có thể sử dụng nó. - tối đa3030

Vâng tất nhiên rồi. Và hầu như tất cả các ứng dụng cần một số loại trạng thái toàn cầu .

Nhưng nhà nước toàn cầu ! = Biến toàn cầu .

Bạn có thể tạo trạng thái toàn cầu bằng các kỹ thuật OO thông qua việc tiêm phụ thuộc Nhưng bạn không thể tránh trạng thái toàn cầu với các cấu trúc tĩnh trạng thái là các biến toàn cục ở phía dưới.


2
Nhà nước toàn cầu không liên quan đến câu hỏi, bất kỳ loại mã nào cũng có thể sử dụng nó.
max630

@ max630 vui lòng xem cập nhật của tôi
Timothy

1
Bạn có thể sử dụng các chức năng miễn phí tĩnh mà không cần khớp nối. Bạn vượt qua Func<Result, Args>các đối tượng, được khởi tạo ở nơi khác.
Caleth

1
1) Tôi thường nghĩ rằng việc thực hiện ẩn là một điều tốt, nơi nó phù hợp. 2) Có tất cả mọi thứ như là đối số / phụ thuộc được đưa vào cũng tạo ra một loại khớp nối thời gian thiết kế, bạn có thể cảm thấy điều này khi bạn thấy mình phải dành nhiều thời gian để thay đổi chữ ký trong chuỗi phụ thuộc dài. Và giống như có mọi chức năng duy nhất yêu cầu Logger của bạn hoặc các mối quan tâm xuyên suốt khác, như một đối số, urgh ... (Nhưng vâng, nó có thể làm cho việc kiểm tra cấp thấp trở nên khó khăn hơn) 3) Tất nhiên các hàm tĩnh nên không trạng thái.
Alex

1
@Alex Sau đó, hãy để tôi nói theo cách khác: Một đơn vị là bất kỳ nhóm mã nào (bao gồm các phương thức "tiện ích" được tham chiếu tĩnh) có cùng lý do để thay đổi . Bất cứ điều gì trong đơn vị này là chi tiết thực hiện . Bất cứ điều gì khác là một sự phụ thuộc và đơn vị không nên có quyền truy cập tĩnh vào nó.
Timothy Truckle
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.