Lớp tĩnh miễn là chúng được sử dụng ở đúng nơi.
Cụ thể: Phương pháp là phương pháp 'lá' (chúng không sửa đổi trạng thái, chúng chỉ biến đổi đầu vào bằng cách nào đó). Ví dụ tốt về điều này là những thứ như Path.Combine. Những thứ này hữu ích và tạo ra cú pháp terser.
Các vấn đề tôi có với tĩnh rất nhiều:
Thứ nhất, nếu bạn có các lớp học tĩnh, phụ thuộc là ẩn. Hãy xem xét những điều sau đây:
public static class ResourceLoader
{
public static void Init(string _rootPath) { ... etc. }
public static void GetResource(string _resourceName) { ... etc. }
public static void Quit() { ... etc. }
}
public static class TextureManager
{
private static Dictionary<string, Texture> m_textures;
public static Init(IEnumerable<GraphicsFormat> _formats)
{
m_textures = new Dictionary<string, Texture>();
foreach(var graphicsFormat in _formats)
{
// do something to create loading classes for all
// supported formats or some other contrived example!
}
}
public static Texture GetTexture(string _path)
{
if(m_textures.ContainsKey(_path))
return m_textures[_path];
// How do we know that ResourceLoader is valid at this point?
var texture = ResourceLoader.LoadResource(_path);
m_textures.Add(_path, texture);
return texture;
}
public static Quit() { ... cleanup code }
}
Nhìn vào TextureManager, bạn không thể biết những bước khởi tạo nào phải được thực hiện bằng cách xem hàm tạo. Bạn phải đào sâu vào lớp để tìm phụ thuộc của nó và khởi tạo mọi thứ theo đúng thứ tự. Trong trường hợp này, nó cần ResourceLoader được khởi tạo trước khi chạy. Bây giờ mở rộng cơn ác mộng phụ thuộc này và bạn có thể đoán điều gì sẽ xảy ra. Hãy tưởng tượng cố gắng duy trì mã khi không có thứ tự khởi tạo rõ ràng. Tương phản điều này với tiêm phụ thuộc với các trường hợp - trong trường hợp đó mã sẽ không ngay cả biên dịch nếu các phụ thuộc không được đáp ứng!
Hơn nữa, nếu bạn sử dụng các số liệu thống kê sửa đổi trạng thái, nó giống như một ngôi nhà của thẻ. Bạn không bao giờ biết ai có quyền truy cập vào cái gì, và thiết kế có xu hướng giống với một con quái vật spaghetti.
Cuối cùng, và cũng quan trọng hơn, việc sử dụng các thống kê liên kết một chương trình với một triển khai cụ thể. Mã tĩnh là phản đối của thiết kế cho testability. Mã thử nghiệm bị thủng với statics là một cơn ác mộng. Một cuộc gọi tĩnh không bao giờ có thể được hoán đổi cho một phép thử kép (trừ khi bạn sử dụng các khuôn khổ thử nghiệm được thiết kế đặc biệt để loại bỏ các kiểu tĩnh), vì vậy một hệ thống tĩnh làm cho mọi thứ sử dụng nó trở thành một thử nghiệm tích hợp ngay lập tức.
Tóm lại, các số liệu thống kê là tốt cho một số thứ và đối với các công cụ nhỏ hoặc mã số tôi sẽ không khuyến khích sử dụng chúng. Tuy nhiên, ngoài ra, họ là một cơn ác mộng đẫm máu để bảo trì, thiết kế tốt và dễ dàng kiểm tra.
Dưới đây là một bài viết tốt về các vấn đề: http://gamearchitect.net/2008/09/13/an-anatomy-of-despair-managers-and-contexts/
Đây chính là vấn đề tôi phải giải quyết - việc sử dụng, hay đúng hơn là sử dụng sai mục đích của các đối tượng Singleton. – overslacked
Cảm ơn bạn vì câu trả lời xuất sắc nhất. Câu hỏi của tôi là, nếu các singletons được truyền vào như các tham số cho các phương thức tĩnh, điều đó có làm cho phương thức tĩnh không an toàn không? –
Thuật ngữ "hàm thuần túy" và "hàm số không tinh khiết" là các tên được đặt trong lập trình chức năng cho những gì bạn gọi là "an toàn" và "không an toàn" thống kê. – Omnimike