繁体   English   中英

Static 到非静态重构,不能两者兼得?

[英]Static to non-static refactoring, can't have both?

我有一个重构情况,我找不到一个优雅的解决方案......

免责声明:请记住,我过度简化了这个示例以减少混乱,并且不透露我不允许透露的内容:) 因此,请不要假设这是我庞大的代码库中唯一的代码,并提供削减的解决方案我提到的设计的角落或更改部分由于外部限制而无法更改。

事实:

我有一个实用程序 class,它有一堆 static 方法,它们使用 singleton 资源:


public final class Utility
{
   private static final Resource RES = Resource.getInstance();
   
   private Utility() {}  // Prevent instantiating Utility
   
   public static boolean utilMethodOne() { return RES.isSomething(); }
   public static int utilMethodTwo() { RES.getNumThings(); }
   ...
   public static void utilMethodInfinity() { ... }
}

实用程序位于库 JAR 中,该库被大型代码库中的多个应用程序使用——假设对其 static 方法的调用量约为 10,000 次,例如: if(Utility.utilMethodOne()) {... }

资源是来自另一个库 JAR 的外部 class。

Resource 还有一个方法 Resource.getInstance(String name) 将返回一个命名实例,该实例可能与基于名称的不同底层资源相关(在内部它将命名资源保存在 Map<String,Resource> 中)。

Resource.getInstance() 返回 Resoruce.getInstance("") 的等价物,也就是默认实例。

情况:

该实用程序需要增强以现在针对多个资源之一执行,因此我的计划是使该实用程序成为具有非静态资源成员变量的可实例化 class。 像这样的东西:


public final class Utility
{
   private Resource res;
   
   public Utility(String resName)
   {
      this.res =  = Resource.getInstance(resName);
   }
   
   public boolean utilMethodOne() { return this.res.isSomething(); }
   public int utilMethodTwo() { this.res.getNumThings(); }
   ...
   public void utilMethodInfinity() { ... }
}

现在这一切都很棒,我可以开始创建访问其指定资源的 Utility 对象,而不仅仅是默认资源。 但是,正如我所提到的,现在有 10-100K 方法调用无效,因为它们正在调用 static 方法!

问题:

我的计划是将 static 方法保留在 Utility 中,并让它们使用 Resource 中的默认实例,同时为使用其“本地”资源引用的实例化 Utility 对象添加非静态变体。


   // Best of both worlds:
   public static boolean utilMethodOne() { return RES.isSomething(); }
   public boolean utilMethodOne() { return this.res.isSomething(); }

也许我不能吃蛋糕也不能吃:


error: method utilMethodOne() is already defined in class Utility
   public static boolean utilMethodOne(String sql)

所以看来我将不得不...

  1. 为想要使用命名资源的地方引入全新的 BetterUtility class。
  2. 更新 10,000 个位置以实例化和使用修订后的实用程序 object。
  3. ...? (提示:这是您的建议的来源!)

由于各种原因,我真的不喜欢 1 或 2,所以我需要确保在解决之前没有更好的 3 选项。 在这种情况下,有没有办法保留一个可以同时提供 static 和非静态接口的 class ?

更新 2020-06-01:

我开始意识到这个神奇的选项 3 不存在。 因此,在我最初的两个选项中,我认为#2 是最好的,因为它只是一次“把它移开并完成它”类型的努力。 还在设计中纳入了您的一些建议。

所以现在我有了一个方向,我只剩下[希望只有]一个关键决定......

  1. 更新所有调用以创建新对象

// For a one-off call, do it inline
boolean foo = new Utility("res1").utilMethodOne();


// Or when used multiple times, re-use the object
Utility util = new Utility("res1");
boolean foo = util.utilMethodOne();
int bar = util.utilMethodTwo();
...

考虑到使用的数量/频率,这似乎是在浪费大量精力来创建短暂的对象。

  1. 遵循资源本身使用的模式,创建我自己的命名单例 map 实用程序(1:1 与它们各自命名的资源)

public final class Utility
{
   private static final Map<String,Utility> NAMED_INSTANCES = new HashMap<>();

   private Resource res;

   private Utility(String resName)
   {
      this.res = Resource.getInstance(resName);
   }
   
   public static Utility getInstance(String resName)
   {
      synchronized(NAMED_INSTANCES)
      {
         Utility instance = NAMED_INSTANCES.get(resName);
         if(instance == null)
         {
            instance = new Utility(resName);
            NAMED_INSTANCES.put(resName, instance);
         }

         return instance;
      }
   }

   public boolean utilMethodOne() { return this.res.isSomething(); }
   public int utilMethodTwo() { this.res.getNumThings(); }
   ...
   public void utilMethodInfinity() { ... }
}


// Now the calls can use
Utility.getInstance("res1")

// In place of
new Utility("res1")

所以基本上这归结为 object 创建与同步 + map 在每次使用时查找。 这里可能有点过早的优化,但我可能不得不长期坚持这个决定。

2020 年 6 月 29 日更新:

不想在这里留下“互联网死胡同”……我最终确实按上述方式更新了所有呼叫站点(包括 2020-06-01 更新中的选项 #2)。 它已经通过了所有测试,并且在各种应用程序中已经在生产环境中运行了一周左右。

It seems that you may want to turn the Utility into a singleton map that will have the same static methods that access the singleton without any arguments on for the function invocations (just like you have now)

singleton 将支持 static 方法添加新资源,然后您将其添加到 map。

此外,您可以重载现有方法以接受参数资源名称,然后使用 map 中的特定资源,否则将使用 map 中的默认条目。

保留旧方法和新方法 static。

private static final String DEFAULT = "RESOURCE1";
private static Map<String, Resource> resources = new HashMap();
static{
// initialize all resources
}
public static boolean utilMethod() { return resources.get(DEFAULT).isSomething(); }
public static boolean utilMethod(String resourceName) { return resources.get(resourceName).isSomething(); }

暂无
暂无

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

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