Как удалить программу Java - PullRequest
5 голосов
/ 18 июня 2011

Позвольте мне начать с того, что я хочу сделать, а затем поднять некоторые вопросы, которые у меня есть.

Я хочу разработать общую программу на Java, которая представляет собой расширенный набор программ (назовем их вариантами программ).В частности, общая программа имеет методы, которые используются только одним или несколькими вариантами программы (но не всеми).Учитывая конкретную конфигурацию, я хочу удалить ненужные методы и просто оставить наименьший набор методов для одного варианта программы.

Например, у меня есть общая программа, как показано ниже:

public class GeneralProgram {

    // this method is common for all variants
    public void method1() {};

    // this method is specific to variant 1
    public void method2() {};

    // this method is specific to variant 2
    public void method3() {};
}

Затем, после удаления программы на основе конфигурации для варианта 1, получается

public class GeneralProgram {

    // this method is common for all variants
    public void method1() {};

    // this method is specific to variant 1
    public void method2() {};
}

Не имеет значения, совпадает ли имя полученного класса с исходным или нет.Я просто хочу сократить содержание класса.

Итак, вот мои вопросы:

  1. У вас есть идеи, как это реализовать, кроме низкоуровневой обработки текста?

  2. Я знаю, что могу использовать аспектJ для отключения / включения определенных методов во время выполнения, но я действительно хочу выполнить эту задачу перед развертыванием программы.Есть ли какая-либо техника в Java для этой цели?

Ответы [ 2 ]

6 голосов
/ 18 июня 2011

Мне кажется, что правильным решением здесь является использование некоторого объектно-ориентированного программирования и создание слоя вашей программы:

base.jar содержит:

package foo.base;
class GeneralProgram {
   public void method1(){ }
}

var1.jar содержит:

package foo.var1;
import foo.base.GeneralProgram;
class GeneralProgramVar1 extends GeneralProgram {
   public void method2(){ }
}

var2.jar содержит:

package foo.var2;
import foo.base.GeneralProgram;
class GeneralProgramVar2 extends GeneralProgram {
   public void method3(){ }
}

В некоторых развертываниях будут присутствовать и base.jar, и var1.jar, в других - base.jar и var2.jar. Вам придется немного поработать с путями к классам, чтобы разрешить зависимости.


Если вы можете достаточно хорошо разделить ваши варианты, чтобы были действительно неиспользуемые функции, то вы можете использовать утилиту сжатия, такую ​​как ProGuard , чтобы удалить неиспользуемые методы из классов. Однако вы можете обнаружить, что усилия, необходимые для получения преимуществ ProGuard, такие же, как и структура, которую я рекомендую выше.

3 голосов
/ 18 июня 2011

@ Ответ Марка Эллиота дает вам «правильный способ» сделать это.

Существует ряд причин, по которым ваш путь не является хорошей идеей вообще, и для приложений Java в частности:

  • Java не поддерживает это. В частности, он не поддерживает условную компиляцию.

  • Хотя препроцессоры исходного кода иногда используются, основные цепочки инструментов Java их не поддерживают. (То же самое относится к (гипотетическим?) Инструментам, работающим на уровне байт-кода ... хотя это не то, о чем вы, кажется, говорите.)

  • С вариантами условной компиляции легче, чтобы изменения, сделанные в одном варианте, сломали другой. (Напротив, хороший дизайн O-O изолирует код, зависящий от варианта, от определенных классов, где они не могут влиять на поведение других вариантов.)

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

  • Варианты условной компиляции усложняют тестирование. Вы в основном должны рассматривать каждый вариант как отдельное приложение, которое должно быть проверено отдельно. Это делает написание тестов более сложным, а выполнение тестов - более дорогим. (И тестирование вариантов очень важно из-за хрупкости баз кода, которые полагаются на условную компиляцию; см. Предыдущий.)

  • Анализ покрытия тестом сложнее / больше работает с вариантами из-за проблем с инструментом; см. предыдущий.


В комментарии ОП пишет:

Так что неэффективно, если я разверну ненужные ресурсы (например, методы, классы, специфичные для других вариантов) для определенного варианта.

Что вы подразумеваете под "неэффективно" ?

В большинстве случаев просто не имеет значения, что база кода включает функциональные возможности, которые не используются в определенных случаях использования или на определенных платформах. Java-приложения используют много памяти, и размер кода обычно не является основной причиной этого. Короче говоря, в большинстве случаев"эффективно" развертывать код, который не будет использоваться: он выполняет свою работу, а накладные расходы не действительно имеют значение.

Если у вас есть одно из этих необычных приложений, в которых размер файла JAR или использование памяти кода действительно значительны (и не только предполагаются), вам все равно не нужно прибегать к условной компиляции или байт-коду взлом.

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

  • Если использование памяти является критической проблемой, вы можете структурировать свой код так, чтобы он использовал динамическую загрузку для загрузки вариантов, платформы или даже конкретных сценариев использования.

...