代码之家  ›  专栏  ›  技术社区  ›  sean717

我应该使这个类静态化吗?

c#
  •  5
  • sean717  · 技术社区  · 14 年前

    在我从事的项目中,我有查询/更新数据库的类,比如这个类,

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

    随着我不断地创建这种类型的类,我意识到也许我应该创建这种类型的类 静止的 . 这样做的明显好处是避免每次需要查询数据库时都需要创建类实例。但是对于静态类,只有一个类副本,这会导致数百个请求只争用一个静态类副本吗?

    谢谢,

    5 回复  |  直到 14 年前
        1
  •  2
  •   DanDan    14 年前

    这要看情况而定。你需要让你的程序多线程吗?您是否需要连接到多个数据库?你需要在这个类中存储状态吗?是否需要控制连接的生存期?将来是否需要数据缓存?如果您对其中任何一个回答“是”,静态类将使事情变得尴尬。

    我个人的建议是让它成为一个例子,因为这是一个更OO,并将给您在未来可能需要的灵活性。

        2
  •  12
  •   brainimus user417509    14 年前

    我不会让那个类保持静态,但会 使用依赖注入并将所需资源传递给该类 . 通过这种方式,您可以创建一个模拟存储库(实现IRepository接口)来进行测试。如果您使类成为静态的,并且不在存储库中通过,那么测试将非常困难,因为您无法控制静态类连接到的是什么。

    注意:下面的代码是一个粗略的示例,仅用于传达要点,不必编译和执行。

    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;
       }
    }
    

    要测试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();
    

    我不想漫谈依赖性注射。 Misko Hevery's blog 用一个 great post to get started .

        3
  •  1
  •   hvgotcodes    14 年前

    您必须小心使这个类成为静态的。在Web应用程序中,每个请求都在自己的线程上处理。如果不小心,静态实用程序可能是线程不安全的。如果发生这种情况,你就不会快乐。

    我强烈建议您遵循DAO模式。使用一个像弹簧这样的工具来让这对你来说很容易。您所要做的就是配置一个数据源,您的数据库访问和事务将是轻而易举的。

        4
  •  0
  •   Adam Houldsworth    14 年前

    如果使用静态类,则必须将其设计为在很大程度上是无状态的。通常的策略是用公共的数据访问函数创建一个基类,然后在特定的类中为客户(比如,加载客户)派生它们。

    如果对象创建实际上是整个操作的开销,那么您还可以查看池中预先创建的对象。然而,我非常怀疑这是事实。

    您可能会发现许多常见的数据访问代码可以被转换成静态方法,但是所有数据访问的静态类似乎都在某个地方丢失了设计。

    静态类本身不存在多线程访问的任何问题,但显然锁和静态或共享状态是有问题的。

        5
  •  0
  •   bottlenecked    14 年前

    通过将类设置为静态的,您将很难对其进行时间单元测试,就像这样 可能必须在内部以一种不清晰的方式管理连接字符串的读取,方法是从配置文件在类内部读取它,或者从管理这些常量的某个类请求它。我宁愿用传统的方式来例示这样一个类

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

    然后将它赋给全局/公共静态变量,如果这对类有意义的话,即

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

    因此,现在您不会为单元测试牺牲任何灵活性,因为类的所有依赖项都是通过其构造函数传递给它的。