是否建议使用保持状态的静态变量?

时间:2010-12-13 08:02:42

标签: java oop design-patterns object static-methods

我有一个依赖外部依赖的加密实用程序方法---一个从属性文件中检索的密码密钥。在我继承的当前代码库中检索它的方式是它依赖于创建新对象以便能够在属性文件中获取属性的值。例如,如果想从属性文件中获取密码密钥,它将是这样的:

    public synchronized static String encrypt(String someTextToEncrypt) {
             String propertyValue = null;
             propertyValue = getProcessCommonBase().
                                getProcessProperties.getProperty("CIPHER_KEY");
                     /*encrypt algorithm*/
             return encryptedForm;
        } 
    private synchronized static ProcessCommonBase getProcessCommonBase() {
            if (processCommonBase == null) {
                 processCommonBase = new ProcessCommonBase();
            }
            return processCommonBase;
    }
    private static ProcessCommonBase processCommonBase;

已编辑:设计明智是有一个像processCommonBase实例变量这样的好习惯吗?我的理解是,一个好的做法是静态变量应该是最终的并且不会改变。但是,在这种情况下,ProcessCommonBase类维护状态并且可能会发生变化。

新问题:如果静态方法依赖于外部的东西我不应该只将方法和processCommon基本变量标记为非静态,而在Spring中,只需为它做一个bean定义?什么是更好的?

3 个答案:

答案 0 :(得分:1)

有人已经评论过你的具体案例,但总的来说,你所描述的是一个有效的最终静态变量,它只是“懒惰地”创建(即只在需要时)。这是一个很好的方法,如果创建一个ProcessCommonBase实例是一个昂贵且罕见的事件,尽管你必须小心只能通过getter方法访问它。另一方面,如果在使用周围类时将创建ProcessCommonBase,那么将其设为最终是一种更好的方法:它更简单(不易出错,因为您不需要记住使用getter方法,并且实际上会更便宜一点,因为最终变量仅在首次使用周围类时初始化,并且每次访问时都不需要(synchronized!)null检查(当然,如果你使用> 1个线程并且ProcessCommonBase不是线程安全的,那么你需要在某处同步。)

回答第二个问题:静态与非静态并依赖于某些外部系统属性是两回事。我不知道Spring做了什么,但是如果你的方法本质上是一个函数 - “输入值,结果输出” - 那么它本质上就是一个静态方法,即使它从某个系统属性读取它的配置。制作这样的方法实例方法是可能的,但如果它只使事情变得复杂并且什么都不给,那为什么要麻烦?

答案 1 :(得分:1)

我同意Joonas。我不明白为什么不让变量最终。你能详细说明一下你的意思是什么:

  

我的理解是,一个好的做法是静态变量应该是最终的并且不会改变。但是,在这种情况下,ProcessCommonBase类维护状态并且可能会发生变化。

即使变量是最终变量,您仍然可以使用与非最终变量完全相同的方式更改它引用的对象。这就是为什么静态方法使静态变量保持其状态完全没问题,但在这种情况下,没有什么能阻止你实际使它成为最终的。为什么不这样做:

private static ProcessCommonBase processCommonBase = new ProcessCommonBase();

也许有些东西会阻止你在静态初始化时创建processCommonBase,但是从你提供的信息来看并不明显。

答案 2 :(得分:0)

从OO设计的角度来看,静态的使用常常令人不悦,因为它提供了对象之间的紧密耦合。使用静态方法,不可能将接口与其实际实现分离。例如,当您想要对单个类进行单元测试时,这种解耦的缺乏会成为一个问题,因为它无法与其他静态部分分开。

在今天的Java环境中,你可以在Dependency Injection(DI)的帮助下更好地设计单独的密码类。 ProcessCommonBase也可以作为DI单例实现,如果它没有那么强的代码味道,因为如果它是god-object那么它应该被重构,例如通过使用DI将属性注入到crypt类中。

基于Google Guice的示例代码:

@Singleton
public MyCrypt {
  private final key;

  @Inject
  MyCrypt(@CipherKey String key) {
    this.pBase = pBase;
  }

  public synchronized String encrypt(String someTextToEncrypt) { 
    /*encrypt algorithm*/ 
    return encryptedForm; 
  }  
}

配置DI属性:

public class PropertiesModule extends AbstractModule {

  @Override
  protected void configure() {
    String key = .. what ever ..
    bind(String.class).annotatedWith(CiperKey.class).toInstance(key);
  }

更多DI示例可在此处找到: http://java.dzone.com/articles/cdi-overview-part-1

Populair Java DI实施是:GuiceSpringJava EE6