java - 降低环复杂度的方法

标签 java cyclomatic-complexity

我从事一个大型java项目(移动应用程序),并且由于性能不佳(高复杂性)而得到了审查和优化/重构代码的“感激”工作。 注意:我对 Java 完全陌生(我的背景是 C/C++),因此我同意任何愚蠢的问题。 我做的第一件事是使用 Findbugs 并修复所有报告的问题。之后我使用度量工具Understanding来获得一个概述,其中 方法具有较高的圈复杂度。不幸的是,有很多方法的圈复杂度高于 2^20 范围:-( 其中之一是我需要一些帮助或好主意......

简短描述: 为了与服务器通信,数据必须被序列化。此移动框架上没有可用的可序列化接口(interface)。 因此,(单独)编写所有代码的同事实现了一个 Serialized 接口(interface),其中包含一个名为 toByteArray() 的方法。 例如,类 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-cases,具体取决于类中有多少属性,因此路径计数变得越来越高。 我认为这不是一个完美的解决方案,但没关系。我想更改的是 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 编码) 或日期和时间?如果我将它们打包在一个类中是一个好的解决方案吗?我从中得到了什么吗?可维护代码?高性能代码?? 您的方法是什么?

谢谢

最佳答案

也许最好为每个类创建一个属性映射。默认情况下,集合是空的,但可以随时调用,例如setAddress(address) 我们调用 fieldsMap.put(ADDRESS_KEY_STRING,address) 而不是分配给类的字段。

要存储所有访问(现有)属性,我们只需通过存储每个条目的 fieldsMap 即可。

关于java - 降低环复杂度的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10380838/

相关文章:

design-patterns - 为什么策略设计模式适用于降低代码的圈复杂度?

javascript - 修复循环内 if/else 的圈复杂度

java - 分割 ScrollView ,使其拉伸(stretch)一半屏幕,但忽略布局权重

java - 如何在android中挂起和恢复线程?

java - 为什么在处理后 JDialog 中 formWindowClosed 被触发两次

java - 如何重新启用屏幕调光?

后续过程的控制流图和圈复杂度

cyclomatic-complexity - 圈复杂度的计算

java - 在Elasticsearch查询结果中隐藏一些数组元素

c# - C# 代码的完整表达式列表,其中圈复杂度为 +1