私は大きなJavaプロジェクト(モバイルアプリケーション)に取り組んでいますが、パフォーマンスが低い(複雑さが高い)ため、コードをレビューして最適化/リファクタリングするという「ありがたい」仕事に就きました。注:私はJavaにまったく慣れていません(私のバックグラウンドはC / C ++です)。したがって、ばかげた質問をお詫びします。私が最初にしたことは、Findbugsを使用して、報告されたすべての問題を修正することでした。その後、メトリックツールUnderstandを使用して、循環的複雑度の高いメソッドの概要を取得しました。残念ながら、2 ^ 20の範囲を超えるサイクロメティックな複雑さを持つメソッドがたくさんありました:-(そしてそれらの1つは、私がいくつかの助けや良いアイデアを必要とする場所です...
簡単な説明:サーバーとの通信では、データをシリアル化する必要があります。このモバイルフレームワークで使用できるシリアル化可能なインターフェイスはありません。したがって、すべてのコードを(単独で)作成した同僚は、と呼ばれる1つのメソッドを含むSerializableインターフェースを実装しましたtoByteArray()
。例class Customer
::
class Customer
{
Address address;
AttributeCollection attributes;
LocationCollection locations;
int recId;
int recStatus;
DateTime recCreated;
String recCreatedBy;
String recCreatedByProg;
DateTime recChanged;
String recChangedBy;
String recChangedByProg;
int refAddressesId;
int refMandatorsId;
CustomerPropertyUsage usage;
/**
* Serialize the properties of a class into a byte array.
* @param destData Byte array, where the serialized data should be stored. Minimum 2 bytes.
* @param serializationIndex Offset within the passed byte array, from which the serialized data of the class
* should be entered. The offset is increased by the registered number of bytes so that after this method the
* next call points to the serialized data subsequent byte.
*/
void toByteArray(byte[] destData, IntClass serializationIndex)
{
if (this.address == null)
this.usage.value &= ~CustomerPropertyUsage.ADDRESS;
if (this.attributes == null)
this.usage.value &= ~CustomerPropertyUsage.ATTRIBUTES;
if (this.locations == null)
this.usage.value &= ~CustomerPropertyUsage.LOCATIONS;
this.usage.toByteArray(destData, serializationIndex);
CatrString catrString = null;
if ((this.usage.value & CustomerPropertyUsage.RECORD_HEADER) != CustomerPropertyUsage.NONE)
{
// Call static method getBytes from SerializationHelper class
SerializationHelper.getBytes(this.recId, 4, destData, serializationIndex.value);
serializationIndex.value += 4;
SerializationHelper.getBytes(this.recStatus, 4, destData, serializationIndex.value);
serializationIndex.value += 4;
// recChanged is a DateTime object. For the serialization we need minimum a 7 bytes array,
// Call method toByteArray() from DateTime class.
this.recChanged.toByteArray(destData, serializationIndex);
// call toByteArray of CatrString class
catrString = new CatrString(this.recChangedBy);
catrString.toByteArray(destData, serializationIndex);
catrString.setValue(this.recChangedByProg);
catrString.toByteArray(destData, serializationIndex);
// Same as recChanged
this.recCreated.toByteArray(destData, serializationIndex);
catrString = new CatrString(this.recCreatedBy);
catrString.toByteArray(destData, serializationIndex);
catrString.setValue(this.recCreatedByProg);
catrString.toByteArray(destData, serializationIndex);
SerializationHelper.getBytes(this.refAddressesId, 4, destData, serializationIndex.value);
serializationIndex.value += 4;
SerializationHelper.getBytes(this.refMandatorsId, 4, destData, serializationIndex.value);
serializationIndex.value += 4;
}
if (next property...)
{
... Serialization ...
}
if (next property...)
{
... Serialization ...
}
}
}
GPRSの会費を低く抑えるために、サーバーはthis.usage.valueに値を設定します。したがって、特定のプロパティのみがシリアル化されてサーバーに返送されます->送信されるメッセージは小さいです。このアプローチでは、クラス内のプロパティの量に応じて多くのif-caseが作成されるため、パス数はますます多くなります。それは美しい解決策ではないと思いますが、大丈夫です。変更したいのは、if-case内のシリアル化呼び出しです。現時点では、次のようになっています。
---- class SerializationHelper ----
static void getBytes(long valueToConvert, int numOfBytesToConvert, byte[] destinationBytes, int destinationBytesOffset)
{
destinationBytes[destinationBytesOffset] = (byte)(valueToConvert & 0x000000FF);
destinationBytes[destinationBytesOffset + 1] = (byte)((valueToConvert & 0x0000FF00) >> 8);
if (numOfBytesToConvert > 2)
{
destinationBytes[destinationBytesOffset + 2] = (byte)((valueToConvert & 0x00FF0000) >> 16);
destinationBytes[destinationBytesOffset + 3] = (byte)((valueToConvert & 0xFF000000) >> 24);
if (numOfBytesToConvert > 4)
{
destinationBytes[destinationBytesOffset + 4] = (byte)((valueToConvert & 0x000000FF00000000L) >> 32);
destinationBytes[destinationBytesOffset + 5] = (byte)((valueToConvert & 0x0000FF0000000000L) >> 40);
destinationBytes[destinationBytesOffset + 6] = (byte)((valueToConvert & 0x00FF000000000000L) >> 48);
destinationBytes[destinationBytesOffset + 7] = (byte)((valueToConvert & 0xFF00000000000000L) >> 56);
}
}
}
---- class CatrString ----
void toByteArray(byte[] destData, IntClass serializationIndex)
{
// Number of unicode characters
SerializationHelper.getBytes(this.textLength, 2, destData, serializationIndex.value);
serializationIndex.value += 2;
// Text UTF-16 unicode characters
for (int charIndex = 0; charIndex < this.textLength; charIndex++)
{
destData[serializationIndex.value] = (byte)(this.charCodes[charIndex] & 0x00FF);
serializationIndex.value++;
destData[serializationIndex.value] = (byte)((this.charCodes[charIndex] & 0xFF00) >> 8);
serializationIndex.value++;
}
// Code End of string as UTF-16 unicode character
destData[serializationIndex.value] = 0x00;
serializationIndex.value++;
destData[serializationIndex.value] = 0x00;
serializationIndex.value++;
}
---- class DateTime ----
void toByteArray(byte[] destData, IntClass serializationIndex)
{
destData[serializationIndex.value + 0] = (byte) (m_year % 0x0100); // year low-Byte.
destData[serializationIndex.value + 1] = (byte) (m_year / 0x0100); // year high-Byte.
destData[serializationIndex.value + 2] = (byte) (m_month);
destData[serializationIndex.value + 3] = (byte) m_day;
destData[serializationIndex.value + 4] = (byte) m_hour;
destData[serializationIndex.value + 5] = (byte) m_minute;
destData[serializationIndex.value + 6] = (byte) m_second;
serializationIndex.value += 7;
}
すべてのシリアル化を行う、より「一般的な」クラスを作成できるはずです。ここで、xyバイトをシリアル化すると、それだけです。しかし、私が理解していないのはtoByteArray()
、文字列(UTF-16エンコーディング)や日付と時刻などの「特別な」メソッドについてはどうでしょうか。私がそれらをクラスに詰めるなら、それは良い解決策ですか?私はそれで何かを得ましたか?保守可能なコード?高性能コード?? あなたのアプローチは何ですか?
どうも