web-dev-qa-db-ja.com

Switchステートメントの循環的複雑度を減らす-Sonar

私のコードが次のようなスイッチケースの循環的複雑度を減らしたい:

public String getCalenderName() {
        switch (type) {
    case COUNTRY:
        return country == null ? name : country.getName() + HOLIDAY_CALENDAR;
    case CCP:
        return ccp == null ? name : ccp.getName() + " CCP" + HOLIDAY_CALENDAR;
    case EXCHANGE:
        return exchange == null ? name : exchange.getName() + HOLIDAY_CALENDAR;
    case TENANT:
        return tenant == null ? name : tenant.getName() + HOLIDAY_CALENDAR;
    default:
        return name;
    }
}

このコードブロックの複雑さは16であり、10に減らしたいと考えています。country、ccp、exchange、tenantは私の異なるオブジェクトです。タイプに基づいて、それぞれのメソッドを呼び出します。

8
Amar Magar

Sonar警告だと思います。 Sonarの警告は必須のルールではなく、単なるガイドだと思います。コードブロックは、そのままREADABLEMAINTAINABLEです。すでに簡単ですが、本当に変更したい場合は、以下の2つのアプローチを試して、複雑さが低くなるかどうかを確認できます。

注:現在コンパイラを持っていないため、エラーが発生する可能性があります。事前に申し訳ありません。

最初のアプローチ:

_Map<String, String> multipliers = new HashMap<String, Float>();
    map.put("country", country);
    map.put("exchange", exchange);
    map.put("ccp", ccp);
    map.put("tenant", tenant);
_

次に、マップを使用して適切な要素を取得できます

_    return map.get(type) == null ? name : map.get(type).getName() + HOLIDAY_CALENDAR;
_

2番目のアプローチ:

すべてのオブジェクトには同じメソッドがあるため、getName()メソッドを含むInterfaceを追加し、次のようにメソッドシグネチャを変更できます。

_getCalendarName(YourInterface yourObject){
    return yourObject == null ? name : yourObject.getName() + HOLIDAY_CALENDAR;
}
_
3
halil

私の知る限り、switchステートメントでreturnステートメントを使用しないでください。変数を使用して、switchステートメントの後にそのロジックを適用します。 null値をチェックするためのメソッドを作成し、スイッチからそのメソッドを呼び出すと、循環的複雑度を減らすことができます。

1
mayank agrawal

Switch/caseステートメントをDictionary>に置き換えることができます。

このブログ投稿 または これ の最後の例を見てください

0
Ammar Hasan

オブジェクト:country、cpp、exchange、tenantが同じインターフェースを共有している場合(例: ObjectWithGetNameを使用すると、次のようにコードをリファクタリングできます。

  public String getCalenderName() {
    ObjectWithGetNameMethod calendarType = null;
    switch (type) {
        case COUNTRY:
           calendarType = country;
           break;
        case CCP:
           calendarType = cpp;
           break;
        case EXCHANGE:
           calendarType = exchange;
           break;
        case TENANT:
           calendarType = tenant;
           break;
        default:
           calendarType = null;
    }
    return (calendarType != null ? (calendarType.getName() + HOLIDAY_CALENDAR) : name);
  }

また、魔女がいろいろな場所で使われているように見えるので、スイッチを別の方法に移すのもいいと思います。

0
Luk

コードで何か他のものが修正されていることを確認するだけで、複雑さを軽減できると思います。

ケースを取る:

case COUNTRY:
  return country == null ? name : country.getName() + HOLIDAY_CALENDAR;

これは、カレンダーの種類がCOUNTRYの場合、カレンダーが関連付けられている国はnullである可能性があることを意味します。これが有効な状況である理由がわからないため、これは設計上防止する必要があるものです。なぜあなたは国のない国のカレンダーを持っているのですか?

したがって、カレンダーにtypeを割り当てたらすぐに、カレンダーにnull以外のオブジェクトが関連付けられていることを確認してください。このようにあなたのケースは次のようになります

case COUNTRY:
  return country.getName() + HOLIDAY_CALENDAR;

これにより、循環的複雑度が5に低下します。

0
Paul Jansen

最初の目的が循環的複雑度を減らすことだけである場合は、次のように、名前を取得する方法ごとにメソッドを作成する必要があります。

 public String getCalenderName() {
    switch (type) {
    case COUNTRY:
        return getCountryName();
    case CCP:
        return getCcpName();
    case EXCHANGE:
        return getExchangeName();
    case TENANT:
        return getTenantName();
    default:
        return name;
    }
}

private String getCountryName() {
    return country == null ? name : country.getName() + HOLIDAY_CALENDAR;
}

private String getCcpName() {
    return ccp == null ? name : ccp.getName() + " CCP" + HOLIDAY_CALENDAR;
}

private String getExchangeName() {
    return exchange == null ? name : getName.toString() + HOLIDAY_CALENDAR;
}

private String getTenantName() {
    return tenant == null ? name : getName.toString() + HOLIDAY_CALENDAR;
}

あなたの特定の例では、(少なくとも)4つの非常によく似た振る舞いを集める1つのクラスがあると思います。たとえば、1つの基本実装(抽象的かどうかに関係なく)と4つの他の継承されたクラスを持つために、リファクタリングは確かにより理にかなっています。

0
Loic M.

すべてのnull比較を削除して、大文字と小文字を切り替える前に確認できます。その場合、複雑さは4減少するか、それ以上になる可能性があります。

0
sandeshch