zoukankan      html  css  js  c++  java
  • 单例模式必亡

    原文:http://www.yegor256.com/2016/06/27/singletons-must-die.html

    因为有很多关于单例模式正在成为一个反模式的文章,我认为把单例模式说成是一个反模式是显而易见的。总之,问题往往是如何不用单例模式来定义一个全局变量,而这个问题的答案对许多人来说并不知道。有很多例子:一个数据库连接池,一个数据访问组件,一个配置文件等等。他们自然看成一个全局变量,但是我们怎么写?

    我相信你已经知道什么是单例模式并且知道为什么它是一个反模式。如果你不知道,我推荐你去读StackOverflow的这篇:为什么单例模式这么糟糕?

    既然我们同意这个糟糕的模式,那如果我们需要应用用不同的方式连接数据库连接池,我们怎么办?我们需要这样:

    class Database {
      public static Database INSTANCE = new Database();
      private Database() {
        // create a connection pool
      }
      public java.sql.Connection connect() {
        // Get new connection from the pool
        // and return
      }
    }

     之后,我们来看JAX-RS REST方法,我们需要从数据库中取出一些东西:

    @Path("/")
    class Index {
      @GET
      public String text() {
        java.sql.Connection connection =
          Database.INSTANCE.connect();
        return new JdbcSession(connection)
          .sql("SELECT text FROM table")
          .fetch(new SingleOutcome(String.class))
      }
    }

    这个例子中你可能对JAX-RS不熟悉,这是一个简单的MVC架构,这个text()方法是一个控制器,另外,我使用的SqlSession是jcabi-jdbc中的一个简单的JDBC封装。

    我们需要Database.INSTANCE成为一个单例,对吗?我们需要它成为全局这样才能任何MVC的控制器可以直接调用它。既然我们都理解并同意单例模式是一个糟糕的东西,我们拿什么来替换它?

    答案是一个依赖注入:

    我们需要让这个数据库连接池依赖控制器,并且保证它又构造器提供。总之,在这个特别的例子里,对于JAX-RS,幸亏它丑陋的架构,我们没有通过构造器来构造。但是我们能够在它contextInitialized()方法中创建ServletContextListener来实例化一个Database。之后,在控制器中,我们通过添加javax.ws.rs.core.Context注释在setter并用getAttribute()方法取回servlet文本内容。这绝对是糟糕死板的,但是这比单例模式好。

    一个合适的面相对象设计会传送一个Database实例给所有需要在构造器中使用的对象。

    无论如何,如果有很多依赖我们怎么办?我们要写一个有10个参数的构造器吗?不,我们不需要。如果我们对象在运行时真的有10个依赖,我们需要把它们切割成更小的对象。

    就是这样,忘记单例模式,不要再使用它。把它们转化成依赖,并且使用new操作符来使他们在各个对象之间传递。

    本文为博主原创文章,转载请在明显位置注明出处: http://www.cnblogs.com/sweng

    本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。

  • 相关阅读:
    Python下载安装
    批量修改样式及全选反选
    小99
    练习题
    练习
    对象、函数
    操作document对象练习
    练习题
    0513-2
    0513-1
  • 原文地址:https://www.cnblogs.com/sweng/p/5655289.html
Copyright © 2011-2022 走看看