5

やりたいことから始めて、疑問点をいくつか挙げてみましょう。

多数のプログラムのスーパーセットである一般的な Java プログラムを開発したいと考えています (それらをプログラムバリアントと呼びましょう)。特に、一般的なプログラムには、1 つまたは複数のプログラム バリアント (ただし、すべてではない) によってのみ使用されるメソッドがあります。特定の構成が与えられた場合、不要なメソッドを削除し、1 つのプログラム バリアントに対して最小限のメソッド セットのみを保持したいと考えています。

たとえば、次のような一般的なプログラムがあります。

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. 実行時にaspectJを使用して特定のメソッドを無効/有効にできることは知っていますが、実際にやりたいのは、プログラムをデプロイする前にこのタスクを実行することです。この目的のためのJavaのテクニックはありますか?

4

2 に答える 2

6

ここでの正しい解決策は、オブジェクト指向プログラミングを使用してプログラムを階層化することだと私には思えます。

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 のメリットを享受するために必要な労力は、上記で推奨する構造と同じであることに気付くかもしれません。

于 2011-06-18T03:28:15.240 に答える
3

@Mark Elliotの答えは、これを行うための「正しい方法」を提供します。

あなたのやり方が一般的に、そして特にJavaアプリケーションにとって良い考えではない理由はいくつかあります:

  • Javaはこれをサポートしていません。具体的には、条件付きコンパイルをサポートしていません。

  • ソースコードプリプロセッサが使用されることもありますが、主流のJavaツールチェーンはそれらをサポートしていません。(バイトコードレベルで動作する(架空の?)ツールについても同じです...それはあなたが話しているようには見えませんが。)

  • 条件付きでコンパイルされたバリアントを使用すると、あるバリアントで行われた変更が別のバリアントを壊しやすくなります。(対照的に、優れたオブジェクト指向デザインは、バリアント固有のコードを、他のバリアントの動作に影響を与えない特定のクラスに分離します。)

  • 条件付きコンパイルが横行しているコードベースは、理解するのがはるかに困難です。

  • 条件付きコンパイルバリアントは、テストをより複雑にします。基本的に、各バリアントを個別にテストする必要がある個別のアプリケーションとして扱う必要があります。これにより、テストの作成がより複雑になり、テストの実行に費用がかかります。(条件付きコンパイルに依存するコードベースは脆弱であるため、バリアントのテストは重要です。前を参照してください。)

  • ツールの問題のため、テストカバレッジ分析はより困難です/バリアントでより多くの作業が行われます。前を参照してください。


コメントで、OPは次のよ​​うに書いています。

したがって、特定のバリアントに不要なリソース(メソッド、他のバリアントに固有のクラスなど)をデプロイすると効果的ではありません。

「効果がない」とはどういう意味ですか?

ほとんどの場合、コードベースに特定のユースケースや特定のプラットフォームで使用されていない機能が含まれていることは問題ではありません。Javaアプリケーションは大量のメモリを使用し、コードサイズは一般的にこれの主な原因ではありません。要するに、ほとんどの場合、使用されないコードをデプロイすることは「効果的」です。それは仕事をし、オーバーヘッドは実際には重要ではありませ

JARファイルのサイズやコードメモリの使用量が非常に重要である(単なる仮想的な問題ではない) 珍しいアプリケーションの1つがある場合でも、条件付きコンパイルやバイトコードハッキングに頼る必要はありません。

  • JARファイルのサイズが重大な問題である場合、ツールが使用しないと判断したクラスとメソッドを取り除くツールがあります。たとえば、アプリケーションが指定されたメソッドから開始されると想定しますmain

  • メモリ使用量が重大な問題である場合は、動的ロードを使用してバリアント、プラットフォーム、またはユースケース固有のクラスをロードするようにコードを構造化できます。

于 2011-06-18T06:43:11.670 に答える