Tôi có nên sử dụng các lớp tĩnh cho các phương thức sẽ thực hiện các tác vụ phổ biến và sẽ được gọi thông qua ứng dụng của tôi không?


8

Tôi đã dành vài giờ qua để đọc về việc sử dụng các staticlớp học và cố gắng tìm hiểu xem tôi có nên sử dụng chúng hay không nhưng vẫn chưa đưa ra kết luận nào. Có vẻ như cuộc tranh luận có thể đi một trong hai cách. Trong ứng dụng của mình, tôi đã tạo ra cái mà tôi gọi là "các lớp trợ giúp" chứa các phương thức sẽ thực hiện các nhiệm vụ rất phổ biến đối với tôi và sẽ được gọi ra khỏi ứng dụng của tôi ( ASP.Net MVCsử dụng Ứng dụng Web C#) và câu hỏi đơn giản là chúng có thực sự tĩnh hay không ?

Đây là một ví dụ về một trong những người giúp đỡ tôi.

public static class ActiveDirectoryHelper
{
    public static PrincipalContext GetPrincipalContext(string ouName)
    {
        var fullOUName = string.Concat("OU=", ouName,",DC=");

        return new PrincipalContext(ContextType.Domain, "", fullOUName, ConfigurationManager.AppSettings["ServiceAccountUser"], ConfigurationManager.AppSettings["ServiceAccountPassword"]);
    }

    public static PrincipalSearcher GetAllUsersInOU(string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        var userPrincipal = new UserPrincipal(principalContext);
        return new PrincipalSearcher(userPrincipal);
    }

    public static UserPrincipal GetUserPrincipal(string userName, string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        return UserPrincipal.FindByIdentity(principalContext, userName);
    }
}

Không có nhiệm vụ để tránh các lớp tĩnh. Sử dụng chúng khi nó hữu ích để làm như vậy. Có những lý do tốt cho các nhà thiết kế ngôn ngữ bao gồm chúng.
Robert Harvey

5
Tại sao bạn không bao gồm các phương thức này làm phương thức tĩnh trong các lớp liên kết của chúng, thay vì đặt tất cả chúng vào một lớp trợ giúp? Ví dụ, phương thức đầu tiên của bạn có thể là một phương thức tĩnh trong PrincipalContextlớp và được gọi là : PrincipalContext.Get(ouName). Đó thực chất là một phương pháp của Nhà máy.
Robert Harvey

@RobertHarvey Tôi không nghĩ mình đang theo dõi. Lớp này nằm trong BLL của tôi và được gọi từ nhiều lớp (bộ điều khiển) khác trên WebUI cũng như Ứng dụng Bảng điều khiển C # bảo trì hàng đêm và để tránh phải viết lại tất cả thời gian tôi chỉ viết nó vào một lớp trợ giúp.
Matthew Verstraete

5
Phát triển phần mềm luôn là một chuỗi sự đánh đổi. Kỹ thuật nào bạn chọn sử dụng tùy thuộc vào bộ đánh đổi nào bạn muốn áp dụng.
Robert Harvey

4
@RobertHarvey: PrincipalContext và UserPrincipal là các lớp thư viện,
kevin cline

Câu trả lời:


3

Tôi nghĩ rằng các lớp tĩnh là tốt đẹp trong nhiều trường hợp. Tôi chỉ có thể nói "sử dụng chúng khi nó hữu ích" nhưng điều đó không hữu ích lắm.

Quy tắc ngón tay cái của tôi là (như mọi khi): Tôi có che giấu bất kỳ sự phụ thuộc nào không? Nếu bạn cảm thấy "lớp người trợ giúp" là hữu ích (mặc dù hãy cẩn thận với sự gắn kết thấp) thì bằng mọi cách, hãy tiếp tục. Chỉ cần chắc chắn rằng phương pháp của bạn không truy cập trạng thái toàn cầu mặc dù. Phương pháp tĩnh tinh khiết là đáng yêu. Các phương thức tĩnh phụ thuộc vào một số toàn cục hoặc mở các kết nối DB hoặc đọc từ đĩa / một số tệp cấu hình đang đánh dấu quả bom hẹn giờ.

Họ làm cho việc kiểm tra ứng dụng thực sự khó khăn (cách duy nhất để thực hiện nó là chạy thủ công toàn bộ hệ thống hoặc với các thử nghiệm toàn hệ thống tự động dễ vỡ, bạn sẽ không bị chi tiết). Họ cũng làm cho nó không thể trao đổi thực hiện.

Chỉ cần nhớ nguyên tắc đảo ngược phụ thuộc và nguyên tắc mở / đóng! Hãy chắc chắn rằng các lớp học của bạn có thể cắm được. Hãy chắc chắn rằng họ không kéo đồ ra khỏi không khí mỏng. Nếu bạn làm điều đó, thì hãy tiếp tục và thực hiện nhiều phương thức tĩnh như bạn muốn!


2

Có vẻ như bạn đang ẩn một phụ thuộc bên ngoài vào Active Directory bằng lớp tĩnh này. Một vấn đề ở đây là nếu bạn đang cố gắng kiểm tra đơn vị lớp gọi các phương thức này, bạn không thể giả mạo các cuộc gọi tĩnh. Vì vậy, bạn ngay lập tức ức chế khả năng kiểm tra mã của bạn. Tôi sẽ cấu trúc lại giao diện này thành một giao diện, giống như IProvideActiveDirectoryInform và lớp cụ thể, ActiveDirectoryInformProvider. Sau đó chuyển giao diện trong hàm tạo của bộ điều khiển của bạn. Điều này sẽ cho phép bạn nối dây lớp bê tông với một thùng chứa DI. Nó cũng sẽ cho phép bạn giả mạo ActiveDirectoryIn informationProvider và trả lại bất cứ thứ gì bạn muốn cho các phương thức giao diện.

Tôi cũng sẽ xem xét việc không trả lại những thứ như đối tượng Hiệu trưởng trong giao diện. Nếu phương thức của bạn là GetAllUsersInOU () tôi sẽ mong đợi một danh sách người dùng hoặc tên người dùng.


Không chắc chắn ý của bạn là gì khi "ẩn một phụ thuộc bên ngoài vào Active Directory". Tôi thực hiện đọc từ AD và lớp này được xây dựng để giảm mã hóa cần thiết để tạo kết nối và nhận dữ liệu cơ bản.
Matthew Verstraete

ý tôi là thế. xem câu trả lời của Kai để được giải thích đầy đủ hơn. Nhưng những gì bạn làm là không làm cho mã của bạn phụ thuộc vào tất cả các phụ thuộc của mã mà bạn gọi.
Fran

1

Một lớp nên tĩnh nếu nó chỉ tồn tại như một khái niệm trừu tượng trong ứng dụng của bạn.

Ví dụ: giả sử bạn đang tạo một bản sao của Twitter. Bạn có thể có 2 loại tweet, tweet người dùng và quảng cáo. Cả hai đều chia sẻ hành vi chung nhưng khác nhau. Vì vậy, bạn muốn sử dụng đa hình và một nhà máy để tạo ra cái này hay cái khác.

Hai lớp tweet đó phải là các lớp cụ thể, vì chúng là các thực thể thực sự. Tên miền của bạn được xác định bởi các lớp này.

Nhà máy phải ở trạng thái tĩnh vì nó chỉ tồn tại ở mức trừu tượng để làm cho ứng dụng của bạn được thiết kế tốt hơn và để giúp bạn sử dụng lại mã sẽ tạo ra một loại tweet. Nhà máy của bạn không được xác định ở bất kỳ cấp nào bởi nhà máy này.

Vì vậy, nếu bạn không nghĩ rằng một lớp nên được khởi tạo nhưng không cần phải mở rộng để sử dụng, thì đó có lẽ là một dấu hiệu tốt cho thấy nó nên tĩnh.


Điều này thực sự sẽ phụ thuộc vào loại nhà máy. Một điều static A BuildA() { return new A(); }chắc chắn đơn giản , điều đó tốt. nhưng nếu bạn cần bất cứ điều gì phức tạp hơn, chẳng hạn như khi A có các phụ thuộc cần tiêm hoặc khi các phần khác nhau trong hệ thống của bạn cần các phiên bản khác nhau của nhà máy (mẫu nhà máy trừu tượng) thì phương thức tĩnh sẽ không cắt.
sara

Cám ơn bạn đã góp ý. Nghe có vẻ như nhà máy mà bạn đang nói đến rất trừu tượng, cuối cùng có vẻ như đó là một khái niệm cụ thể cần được khởi tạo (đặc biệt là khi bạn nói rằng bạn cần nhiều nhà máy khác nhau). Sau đó, một lần nữa, không có gì được đặt trong đá dù thế nào và chỉ có thể đưa ra lời khuyên về chủ đề này.
Steve Chamaillard

1
Tồn tại nhiều thực thể là "Chế tạo thuần túy", không theo bất kỳ cách nào hoặc hình thức dịch sang tên miền, ví dụ như UserDao. Đây không phải là một dấu hiệu cho dù nó có nên tĩnh hay không. Nó nên tĩnh nếu các đơn vị công việc nó làm, không phụ thuộc vào nhau và nên có thể mở rộng, ví dụ lớp Toán.
Chris Wohlert

@ChrisWohlert nhận xét rất thú vị (bật ngón tay cái), nhưng nó không chỉ phụ thuộc vào bối cảnh? Tôi cảm thấy như một ứng dụng về toán học sẽ muốn một lớp Toán trở thành một trong những lớp cốt lõi và có thể thực hiện được. UserDao có phải là một loại kho lưu trữ giữa lớp Người dùng và DB không? Nếu vậy, tại sao bạn muốn khởi tạo nó? Bạn vẫn có thể tiêm nó mặc dù bạn sẽ không bao giờ tạo đối tượng cho việc này, vì nó không "tồn tại", bạn nghĩ sao?
Steve Chamaillard

1
@SteveChamaillard Bạn có giả định này rằng việc khởi tạo chỉ các đối tượng "thực" có ý nghĩa. Nó nhắc nhở tôi những tương tự OOP 101 này trong đó bạn có lớp trừu tượng "Trái cây" và được thừa hưởng "Apple" - nơi các đối tượng OOP đại diện cho các đối tượng trong thế giới thực. Nhưng không cần phải giới hạn bản thân như thế này. OOP là một công cụ, vì vậy mọi người sử dụng các đối tượng cho "chế tạo thuần túy" thậm chí điều đó làm cho cuộc sống của họ dễ dàng hơn và tôi không thấy có gì sai với nó ...
qbd

1

Một trong những điều được đề xuất trong Lập trình hướng đối tượng là Xấu (tiêu đề là thu hút sự chú ý của bạn và nội dung bị tranh cãi nhưng mang tính giải trí) là *Handler, *Manager*Doercác lớp nói chung là một mùi mã cho biết ai đó đang cố gắng hướng đối tượng vào vấn đề phù hợp hơn cho việc thực hiện thủ tục.

Trong C #, bạn có thể sử dụng các lớp tĩnh làm không gian tên mô-đun cho các thủ tục và tốt nhất là đặt tên cho chúng như vậy. Tôi nghĩ rằng đây là cách để làm điều đó, nhưng không phải trong trường hợp cụ thể của bạn.

Các ứng dụng triển khai cụ thể của bạn sẽ có các phụ thuộc hành vi của trạng thái toàn cầu (giả sử các quyền của một người dùng cụ thể) và do đó phải là một phụ thuộc được tiêm để mã sử dụng mã này có thể được kiểm tra đơn vị.


0

Tôi có thể đang thiếu một cái gì đó nhưng trong tâm trí của tôi, câu trả lời tập trung vào các phương thức và các biến thành viên.

Nếu tất cả đều là tĩnh, thì chính lớp đó có thể (và nên) tạo thành tĩnh. Nếu không, thì nó không phải là một lớp tĩnh.

NB không có gì buộc lớp phải tĩnh ngay cả khi các phương thức và biến đều là tĩnh.


Cùng một lớp làm những việc giống nhau có thể được thiết kế thành cả tĩnh và không tĩnh. Luôn luôn có một sự lựa chọn thiết kế được thực hiện.
sara

Có thể có một sự lựa chọn thiết kế nhưng việc thực hiện có phần tùy ý. Không có gì buộc bạn phải gắn nhãn phương thức hoặc lớp tĩnh - ngay cả khi thiếu biến thể hiện mặc dù một số công cụ như ReSharper thực hiện điều này ...
Robbie Dee

Nhưng khi nào tôi nên làm cho tất cả các phương thức / thành viên tĩnh hay không? Đó là câu hỏi. Khi nào nên sử dụng tĩnh và khi nào không.
Matthew Verstraete

Nếu không có biến hoặc phương thức thành viên nào dựa vào một thể hiện của lớp - bạn có cho mình một lớp tĩnh thực sự. Về bản chất, những thứ này có xu hướng là những thứ như các lớp trợ giúp hoặc các tiện ích và những thứ tương tự.
Robbie Dee

0

Hãy xem xét ngôn ngữ lập trình bạn đang sử dụng (C #) như một bộ công cụ.

Không có quy tắc, không "nên" hoặc "không nên".

Nhìn vào công việc đang làm, và chọn công cụ tốt nhất cho công việc.

Nếu bạn cần một tập hợp các phương thức có sẵn trên toàn cầu, giống nhau cho tất cả các luồng, thì các lớp tĩnh là một công cụ tốt. Nếu bạn muốn lưu trữ dữ liệu trong lớp (khác nhau cho mỗi luồng) thì có lẽ chúng không phải.


0

Không có gì sai trong lớp Người trợ giúp của bạn. Tôi phải thú nhận rằng tôi sử dụng loại Utils , Helpers hoặc Chủ sở hữu này để tạo ra các tài nguyên / logic nhất định từ các nơi khác nhau.

Tuy nhiên, một kiến ​​trúc sư của công ty tôi nói với tôi nhiều lần rằng các lớp này thường thu thập mã mà tôi không biết đặt ở đâu. Anh ta cũng không thích vì bạn có thể mang các thành phần từ các lớp mà các lớp trên / dưới không nên có quyền truy cập và chúng thực hiện các nhiệm vụ ngoài khả năng đáp ứng của chúng. Nó cũng mang lại một số vấn đề tại thời gian thử nghiệm.

Tôi không phiền Tôi sử dụng'em và tôi sử dụng đúng như tôi nghĩ nó nên được sử dụng. Và nó hoạt động tốt. Vì vậy, đừng lo lắng.

Đúng là tại thời điểm kiểm tra đơn vị, bạn sẽ khó có thể chế nhạo nó. Nhưng nó sẽ chỉ mất một chút thời gian để làm điều đó. Có những lib đi qua vấn đề này.

Một cách tiếp cận khác có thể ngăn bạn khỏi loại thiếu sót này (lúc kiểm tra). Ví dụ, mẫu Singleton. Tiêm thể hiện như phụ thuộc thành phần và chuyển phương thức sang phương thức thể hiện.

Dù sao, cho đến nay tôi thấy, giải pháp của bạn có vẻ tốt với tôi.

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.