【问题标题】:Singleton Pattern, Configuration and Dependency Injection单例模式、配置和依赖注入
【发布时间】:2019-01-23 22:48:26
【问题描述】:

我目前正在将一个 C 库移植到 Java。 C 库连接到外部设备并提供配置设备和接收数据的功能。我设计的核心是一个Connection 类,它封装了与设备的连接,并提供了使用 JNA 生成的低级 C API 映射。

由于大多数 C 库不能很好地转换为 Java 的 OO-World(包含 100 多个函数的单个头库),因此我有几个“管理器”类可以提供对大部分功能的访问。

创建多个这些类没有意义,因为 C 库只管理所有资源(配置、数据缓冲区等)的一种资源。所以我想为我的 Java 类实现单例模式(实际上也向我的新 Java 库的用户发出信号,整个系统中只有一个 Manager 对象)。

此外,我希望能够使用外部配置文件配置这些管理器类。我以前从未实现过配置实用程序,所以我真的不知道该放在哪里。

最后,我的所有 Manager 类都需要引用 Connection 对象。

所以我需要一个能让我:

  1. 让我的 Java 类独一无二(单例模式)
  2. 注入我的Connection 对象
  3. 使用配置文件配置我的类

有什么想法吗?

【问题讨论】:

    标签: java singleton


    【解决方案1】:

    对于前两点,这样的事情可以解决问题:

    public class Connection{
    
        private static Connection instance = null;
        private String connectionString;
    
        protected Connection() {
        }
    
        public static Connection getInstance() {
           if(instance == null) {
              instance = new Connection();
           }
           return instance;
        }
    
        public void setConnectionString(String connectionString){
            this.connectionString = connectionString;
        }
    
        public String getConnectionString(){
            return this.connectionString;
        }
    }
    

    这是java中单例的经典示例。构造函数是protected,所以不能使用new关键字来实例化它。相反,您可以像这样使用它:

    Connection con = Connection.getInstance();
    

    getInstance() 负责实例化并确保您的单例仅存在一个实例。比如这个:

        Connection con = Connection.getInstance();
        con.setConnectionString("foobar");
    
        Connection con2 = Connection.getInstance();
        System.out.println(con2.getConnectionString());
    

    将打印foobar

    关于第三点,我建议您到this question 那里已经得到答复。

    【讨论】:

    • 我实际上是在谈论将连接注入另一个对象,但我想我也可以使用 setter 注入。你会把配置放在哪里(设计方面)?
    • 可能是一个配置类,它读取配置文件并将其解析为某种数据结构。
    • 然后使用公共的getter和setter配置对象?
    • 您可以使用this answer 进行配置:
    • 这正是我所需要的。谢谢;-)
    【解决方案2】:
    public static Connection getInstance() {
           if(instance == null) {
              instance = new Connection();
           }
           return instance;
    }
    

    这种实现违反了单例原则。考虑使用两种惰性初始化方法之一:

    1. 使用同步关键字 public synchronized static Connection getInstance() { ... }

    2. init-on-demand 持有者习语。

      public final class Connection {
      
          private static class Holder {
              private static final Connection INSTANCE = new Connection();
          }
      
          private Connection() {}
          public static Connection getInstance() { 
              return Holder.INSTANCE;
          }
      }
      

    对此,按需初始化持有者习语是一个惰性同步单例,比第一个使用同步关键字的解决方案性能更高。

    【讨论】:

      猜你喜欢
      • 2021-07-03
      • 2012-02-29
      • 1970-01-01
      • 1970-01-01
      • 2019-05-06
      • 2014-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多