0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【リファクタリング】Change Unidirectional Association to Bidirectional(一方向の関連を双方向に変更)

Posted at

1. 概要(Overview)

Change Unidirectional Association to Bidirectional は、
一方のクラスからしか参照できなかった関連を、双方向で参照可能にするリファクタリングです。

目的は以下の通りです:

  • 双方向のナビゲーションを可能にして、利便性を向上
  • 関連するオブジェクトを相互にたどれるようにする
  • モデルやドメインの表現力を高める

2. 適用シーン(When to Use)

  • クラス A から B へはアクセスできるが、B から A へもアクセスしたい
  • 双方向の関係を持たないとロジックが不自然になる
  • クライアントコードが「A のリストを全部たどって B を探す」ような冗長な処理を書いている

例:

  • OrderCustomer を参照しているが、Customer 側からも Order を見たい
  • TeamPlayer を持っているが、Player から Team にアクセスしたい

3. 手順(Mechanics / Steps)

  1. 片方向の関連を確認(例:Order → Customer
  2. 逆方向の関連を新しく追加(例:Customer → Order
  3. 2つの関連を 同期させるメソッド を導入
  4. 双方向の整合性が崩れないようにテストを追加

4. Kotlin 例(Before → After)

Before:一方向の関連

class Customer(val name: String)

class Order(val id: Int, val customer: Customer)

fun main() {
    val customer = Customer("Alice")
    val order = Order(101, customer)

    println(order.customer.name) // ✅ OK
    // println(customer.orders)  // ❌ Customer から Order をたどれない
}
  • Order からは Customer を参照できる
  • しかし Customer 側からは自分の注文をたどれない

After:双方向の関連に変更

class Customer(val name: String) {
    private val _orders = mutableListOf<Order>()
    val orders: List<Order> get() = _orders

    fun addOrder(order: Order) {
        _orders.add(order)
        if (order.customer != this) {
            order.setCustomer(this) // 双方向の整合性を保つ
        }
    }
}

class Order(val id: Int, private var _customer: Customer? = null) {
    val customer: Customer? get() = _customer

    fun setCustomer(customer: Customer) {
        _customer = customer
        if (!customer.orders.contains(this)) {
            customer.addOrder(this) // 双方向の整合性を保つ
        }
    }
}

fun main() {
    val customer = Customer("Alice")
    val order = Order(101)

    order.setCustomer(customer)

    println(order.customer?.name) // Alice
    println(customer.orders.map { it.id }) // [101]
}
  • 双方向にアクセス可能 (order.customer, customer.orders)
  • setCustomeraddOrder で双方向の整合性を保証

5. 効果(Benefits)

  • 双方向のナビゲーションが可能になり、コードがシンプルに
  • モデルの表現力が高まる(現実世界に近い)
  • 関連の整合性を内部で管理できる

6. 注意点(Pitfalls)

  • 双方向の同期処理が増え、バグ(無限ループなど) を招く可能性がある
  • 双方向にすると依存関係が強まり、結合度が高くなる
  • 「本当に双方向が必要か?」を検討してから導入すること
    • 片方向アクセスで十分ならそのままの方が安全

まとめ

  • Change Unidirectional Association to Bidirectional は「一方向の関連を双方向に変える」リファクタリング
  • 判断基準:その関連は本当に双方向にすべきか?
  • 基本思想:ナビゲーションを簡単にする一方で、整合性維持の責務が増える

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?