简体   繁体   English

我应该让这个类静态吗?

[英]should I make this class static?

In the projects I worked on I have classes that query/update database, like this one, 在我工作的项目中,我有查询/更新数据库的类,就像这个,

public class CompanyInfoManager
{
    public List<string> GetCompanyNames()
    {
         //Query database and return list of company names
    }
}

as I keep creating more and more classes of this sort, I realize that maybe I should make this type of class static . 随着我不断创建越来越多的这类类,我意识到也许我应该使这种类静态 By doing so the obvious benefit is avoid the need to create class instances every time I need to query the database. 通过这样做,显而易见的好处是避免每次需要查询数据库时都需要创建类实例。 But since for the static class, there is only one copy of the class, will this result in hundreds of requests contend for only one copy of static class? 但是因为对于静态类,只有一个类的副本,这会导致数百个请求只争用一个静态类的副本吗?

Thanks, 谢谢,

I would not make that class static but instead would use dependency injection and pass in needed resources to that class . 我不会使该类静态,而是使用依赖注入并将所需的资源传递给该类 This way you can create a mock repository (that implements the IRepository interface) to test with. 这样您就可以创建一个模拟存储库(实现IRepository接口)来进行测试。 If you make the class static and don't pass in your repository then it is very difficult to test since you can't control what the static class is connecting to. 如果你使类静态并且没有传入你的存储库那么它很难测试,因为你无法控制静态类连接的内容。

Note: The code below is a rough example and is only intended to convey the point, not necessarily compile and execute. 注意:下面的代码是一个粗略的例子,仅用于表达这一点,不一定是编译和执行。

public interface IRepository
{
   public DataSet ExecuteQuery(string aQuery);
   //Other methods to interact with the DB (such as update or insert) are defined here.
}

public class CompanyInfoManager
{
   private IRepository theRepository;
   public CompanyInfoManager(IRepository aRepository)
   {
      //A repository is required so that we always know what
      //we are talking to.
      theRepository = aRepository;
   }

   public List<string> GetCompanyNames()
   {
      //Query database and return list of company names
      string query = "SELECT * FROM COMPANIES";
      DataSet results = theRepository.ExecuteQuery(query);
      //Process the results...
      return listOfNames;
   }
}

To test CompanyInfoManager: 要测试CompanyInfoManager:

//Class to test CompanyInfoManager
public class MockRepository : IRepository
{
   //This method will always return a known value.
   public DataSet ExecuteQuery(string aQuery)
   {
      DataSet returnResults = new DataSet();
      //Fill the data set with known values...
      return returnResults;
   }
}

//This will always contain known values that you can test.
IList<string> names = new CompanyInfoManager(new MockRepository()).GetCompanyNames();

I didn't want to ramble on about dependency injection. 关于依赖注入,我不想絮絮叨叨。 Misko Hevery's blog goes into great detail with a great post to get started . Misko Hevery的博客详细介绍了一篇很棒的文章,以便开始使用

It depends. 这取决于。 Will you ever need to make your program multithreaded? 你需要让你的程序多线程吗? Will you ever need to connect to more than one database? 您是否需要连接到多个数据库? Will you ever need to store state in this class? 你是否需要在这堂课中存储州? Do you need to control the lifetime of your connections? 您需要控制连接的生命周期吗? Will you need data caching in the future? 您将来需要数据缓存吗? If you answer yes to any of these, a static class will make things awkward. 如果您对其中任何一个回答“是”,则静态类会使事情变得尴尬。

My personal advice would be to make it an instance as this is more OO and would give you flexibility you might need in the future. 我个人的建议是将它作为一个实例,因为这是更多的OO,并将为您提供将来可能需要的灵活性。

You have to be careful making this class static. 你必须小心使这个类静态。 In a web app, each request is handled on its own thread. 在Web应用程序中,每个请求都在其自己的线程上处理。 Static utilities can be thread-unsafe if you are not careful. 如果不小心,静态实用程序可能是线程不安全的。 And if that happens you are not going to be happy. 如果发生这种情况,你就不会幸福。

I would highly recommend you follow the DAO pattern. 我强烈建议你遵循DAO模式。 Use a tool like Spring to make this easy for you. 使用像Spring这样的工具让你轻松上手。 All you have to do is configure a datasource and your DB access and transactions will be a breeze. 您所要做的就是配置数据源,您的数据库访问和事务将变得轻而易举。

If you go for a static class you will have to design it such that its largely stateless. 如果你去静态课程,你将不得不设计它,使其基本上无国籍。 The usual tactic is to create a base class with common data access functions and then derive them in specific classes for, say, loading Customers. 通常的策略是创建一个具有公共数据访问功能的基类,然后在特定的类中派生它们,比如加载客户。

If object creation is actually the overhead in the entire operation, then you could also look at pooling pre-created objects. 如果对象创建实际上是整个操作的开销,那么您还可以查看池化预先创建的对象。 However, I highly doubt this is the case. 但是,我非常怀疑是这种情况。

You might find that a lot of your common data access code could be made into static methods, but a static class for all data access seems like the design is lost somewhere. 您可能会发现许多常见的数据访问代码都可以构建为静态方法,但是所有数据访问的静态类似乎都在某处丢失了设计。

Static classes don't have any issues with multi-threaded access per-se, but obviously locks and static or shared state is problematic. 静态类本身对多线程访问没有任何问题,但显然锁和静态或共享状态是有问题的。

By making the class static, you would have a hard time unit testing it, as then you would probably have to manage internally the reading of the connection string in a non-clear manner, either by reading it inside the class from a configuration file or requesting it from some class that manages these constants. 通过使类静态,您将有一个艰难的时间单元测试它,因为您可能必须以非清晰的方式在内部管理连接字符串的读取,通过从类配置文件中读取它或从管理这些常量的某个类请求它。 I'd rather instantiate such a class in a traditional way 我宁愿以传统方式实例化这样一个类

var manager = new CompanyInfoManager(string connectionString /*...and possible other dependencies too*/)

and then assign it to a global/public static variable, if that makes sense for the class, ie 然后将其分配给全局/公共静态变量,如果这对于类有意义,即

//this can be accessed globally
public static CompanyInfoManager = manager;

so now you would not sacrifice any flexibility for your unit tests, since all of the class's dependencies are passed to it through its constructor 所以现在你不会为单元测试牺牲任何灵活性,因为所有类的依赖都是通过它的构造函数传递给它的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM