Рефакторинг от статического c до нестатического c, не может быть и того, и другого? - PullRequest
3 голосов
/ 29 мая 2020
• 1000 Мне не разрешено раскрывать информацию :) Поэтому, пожалуйста, не думайте, что это ЕДИНСТВЕННЫЙ код в моей гигантской кодовой базе, и предлагайте решения, которые сокращают углы или изменяют части дизайна, которые я упомянул, не могут быть изменены из-за внешних ограничений.

Факты:

У меня есть служебный класс, в нем есть несколько методов c, они используют одноэлементный ресурс:

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, которая используется несколькими приложениями в большой кодовой базе - скажем, порядка 10 000 вызовов ее методов c stati, например: if (Utility.utilMethodOne ()) {.. .}

Resource - это внешний класс из другой библиотеки JAR.

Resource также имеет метод Resource.getInstance (String name), который возвращает именованный экземпляр, который может относиться к другому базовому ресурс на основе имени (внутри он хранит именованные ресурсы на карте ).

Resource.getInstance () возвращает эквивалент Resoruce.getInstance (""), также известный как экземпляр по умолчанию.

Ситуация:

Утилита должна быть улучшена, чтобы теперь она могла выполняться с одним из нескольких ресурсов, поэтому я планирую сделать утилиту экземпляром класса с нестатической c переменной-членом ресурса. Примерно так:

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() { ... }
}

Теперь все в порядке, и я могу начать создавать служебные объекты, которые обращаются к их указанному ресурсу, а не только к ресурсу по умолчанию. Однако, как я уже упоминал, 10–100 тысяч вызовов методов теперь недействительны, поскольку они вызывали методы stati c!

Проблема:

Мой план заключалась в том, чтобы сохранить методы stati c в Utility и заставить их использовать экземпляр по умолчанию из Resource, при этом добавляя нестандартные c варианты для созданных экземпляров объектов 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 для мест, которые хотят использовать именованные ресурсы.
  2. Обновление 10,000 места для создания и использования измененного объекта Utility.
  3. ...? (подсказка: здесь и появляются ваши предложения!)

Мне действительно не нравятся 1 или 2 по разным причинам, поэтому мне нужно убедиться, что нет лучшего варианта 3 перед тем, как остановиться. Есть ли способ сохранить один класс, который в этом случае может предоставлять интерфейсы как stati c, так и non-stati c?

UPDATE 2020-06-01:

I Прихожу к выводу, что этого волшебного варианта 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: 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")

Итак, по сути, это сводится к созданию объекта по сравнению с синхронизацией + поиском карты при каждом использовании. Вероятно, здесь немного преждевременной оптимизации, но мне, вероятно, придется придерживаться этого решения в долгосрочной перспективе.

ОБНОВЛЕНИЕ 2020-06-29:

Не хотел оставлять " Inte rnet тупик "здесь ... В конечном итоге я получил все сайты звонков, обновленные, как описано выше (включая вариант № 2 из обновления 2020-06-01). Он прошел все испытания и уже около недели работает в различных приложениях.

Ответы [ 2 ]

0 голосов
/ 30 мая 2020

Оставить старые методы и новые методы stati c.

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(); }
0 голосов
/ 29 мая 2020
• 1000 1002 * Синглтон будет поддерживать статический c метод добавления нового ресурса, затем вы добавите его на карту.

Кроме того, вы можете перегрузить существующие методы, чтобы они также принимали имя ресурса аргумента, которое затем будет использовать определенный ресурс с карты, в противном случае будет использоваться запись по умолчанию с карты.

...