LoginSignup
12
6

【Swift】Swiftで学ぶ結合度

Last updated at Posted at 2022-10-02

結合度とは

結合度とは、モジュール同士の関係の密接さを表す尺度です。
モジュールというのは、システムを構成する要素となるもの。具体例を出すと、検索機能や登録機能などのクラスや関数を指します。

つまり、結合度とは、モジュールの影響範囲がどれだけ狭いかを測る尺度です。

各機能において、どこで利用されて、どこで利用されていないかを判断できるよう整理・分割がどの程度されているかを表す尺度です。

凝集度との違い

凝集度は、モジュール内の評価に使われるのに対し、結合度はモジュール間の相互依存性の度合いに使われます。

高凝集を意図して強く関係していそうなロジックを 1 箇所にまとめ上げようとしたものの、結果として密結合に陥るケースは多く見られます。
そのため、それぞれの概念は分離し、疎結合にしなければなりません。(疎結合高凝集

結合度の高い・低い

この結合度は、「結合度が高い」、「結合度が低い」といった言い方で使われます。
基本的に、

  • 単一の機能をモジュールにしたか
  • 複数の機能をモジュールにした場合、関係性や規則性があるか
  • モジュールの入力、出力に共通性、独立性があるか

の 3 つを基準に強度が決定します。

モジュールの影響範囲が狭いと 1 つの事柄に特化していることになるので、

  • 可読性
  • 保守性

の点から、結合度は低い方が望ましいとされています。

結合度のレベル

結合度の高さには、レベルがあります。主に 6 つ存在しており、

  1. 内容結合
  2. 共通結合
  3. 外部結合
  4. 制御結合
  5. スタンプ結合
  6. データ結合

があります。
内容結合の方は「結合度が高い」とされており、データ結合の方が「結合度が低い」とされています。

内容結合

あるモジュールと別のモジュールが一部を共有するようなモジュールの結合を指します。
高水準言語を使用したモジュールには見られませんが、アセンブラ言語などを使用したモジュールではしばしば見られます。

内容結合
private func contentCoupling() -> Void {
    let user = UserData()
    let userId = user.findId(3)
    let output = user.getFirstName(id: userId) + user.getLastName(id: userId)
    print(output)
}

class UserData{
    func findId(_ id: Int) -> Int {
        return id
    }
    
    func getFirstName(id: Int) -> String {
        let firstNameList = ["佐藤", "田中", "高橋", "本田"]
        return firstNameList[id]
    }
    
    func getLastName(id: Int) -> String {
        let lastNameList = ["太郎", "二郎", "サブロー", "四郎"]
        return lastNameList[id]
    }
}

(ソースコードに自信がない・・・)

共通結合

共通結合とは、共通域に定義したデータを、いくつかのモジュールが共同使用するような結合を指します。
「共通域に定義したデータ」の具体的な物の中にグローバル変数があります。
あるモジュールでグローバル変数を変更すると、他のモジュールでも変更されてしまいます。

共通結合
var globalMember: Int = 5

private func add() {
    var privateMember1: Int = 2
    let sum = globalMember + privateMember1
    print("add: \(sum)")
}

private func add2() {
    var privateMember2: Int = 3
    globalMember += 10
    let sum = globalMember + privateMember2
    print("sum: \(sum)")
}

add() // add: 7
add2() // add2: 18
add() // add: 17

これはイメージがつきやすいかと思います。
可変なグローバル変数はいつ何処で変更されるのかわからないのが問題です。
エラーが出た時に容疑者が多いと特定するだけで時間がかかります・・・。

外部結合

外部宣言されたデータを共有したモジュール間の結合を指します。
要は、public 変数のことです。

外部結合
class SampleA {
    var sampleAPrivateMember: Int = 5
    private func add() {
        var privateMember1: Int = 2
        let sum = sampleAPrivateMember + privateMember1
        print("add: \(sum)")
    }
}

private func add2() {
    var privateMember2: Int = 3
    let sampleAMember = SampleA().sampleAPrivateMember + 5
    
    let sum = sampleAMember + privateMember2
    print("add2: \(sum)")
}

共通結合との違いは、不要なデータを共有するか否かです。
共通結合のように、不必要なデータも共有しないので、結合度は弱くなります。

制御結合

呼び出し側のモジュールが、呼び出されるモジュールの制御を支持するデータを、パラメータとして渡す結合を指します。
要は if 文を使って、実行する処理を外部のデータによって制御している状態をさします。

制御結合
func register(userData: Data) {
    
    if userData == "japan" {
        //国内ユーザーの登録
        return
    }
    // 海外ユーザーの登
}

呼び出し側が、呼び出されるモジュールの論理を知っている必要があり、相手をブラックボックス化できず、結合度が強くなります。
ただ、データの共有ということではないので、共通結合や外部結合より結合度は弱いと言えます。

スタンプ結合

共通域にないデータ構造を、2 つのモジュールで受け渡しするような結合を指します。

スタンプ結合
func findUserEmail() {
    return UserData().findByUserName(User().name)
}

特別問題がなさそうなコードに見えますが、User インスタンスを渡しているため、User インスタンスに依存している状態です。
そのため、User クラスから name プロパティが削除されると、エラーが発生します。

データ結合

モジュール間のインターフェースとして、型のデータ要素だけを、パラメータとして受け渡す結合を指します。

データ結合
private func findUserEmail(name: String, id: Int) {
    let user = User()
    user.addName(name)
    user.addIdFilter(id)
    return userData().findbyUser(user)
}

受け渡すのがデータ構造で、その一部だけを利用します。
そのため、相手モジュール(今回は User())をブラックボックス化できるので、結合度は一番弱くなります。

まとめ:参照透過性

違います。

ある関数が、同じ入力に対して同じ作用、同じ出力を持つプログラムを指します。
具体例を挙げると、数学には参照透過性があります。
$y = 2 x + 3$という一次関数は、入力$x = 1$に対して、出力$y = 5$を返します。
これは、どの値でも同じ処理、同じ出力を返します。

それに対し、プログラムはグローバル変数などによる副作用により、異なる処理や値を返す場合があります。
今回の記事「結合度」で紹介した結合度の高いメソッドなどがその例です。

参照透過性のメリットは、メソッド、変数について値を参照する必要がありません。
故に、「参照について透過的な性質」→「参照透過性」ということです。

参考文献

参照透過性

12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6