Modifier.NodeとModifier.Elementの関係を理解する
Jetpack Composeのパフォーマンス改善のためにModifier.composedからModifier.Nodeへの移行が進められています。自分の作ったライブラリもModifier.Nodeに移行したいと思って調べ始めたのですが、インターフェースや抽象クラスがたくさん出てきて全体像を把握するのが難しかったので、Modifier.ElementやModifier.Nodeといった登場人物の関連を整理して、全体の構成を俯瞰できるようにしてみました。私も調べながらこの記事を書いているので、もし間違いがあったらTwitterなどでご指摘いただけるとありがたいです。
Modifier.ElementとModifier.Nodeの関係
まず、Modifier.ElementとModifier.Nodeについて理解しておきたい前提があります。Modifier.Elementは、Modifierチェーンを構成する要素です。Modifierチェーンとは、Modifier.fillMaxSize().clickable{}.background()....のようにModifier修飾子をつなげた構造のことで、このチェーンの一つ一つがModifier.Elementで構成されています。しかし、Modifier.Elementが直接UIの描画に使われるわけではありません。一つのModifier.Elementにつき、一つのModifier.Nodeが作成され、これがLayoutに適用されることによってUIに反映されます。
このModifier.ElementとModifier.Nodeの関係は、Android Dev Summit 2022の動画で説明されています。
動画から2つのスライドを引用します。

Modifier.Elementでチェーンが構成され・・・

個々のModifier.ElementからModifier.Nodeが作成され、Layoutに適用されます。
クラス構成
では、この前提を踏まえた上で、Modifier.NodeとModifier.Elementの周辺のクラス図を見ていきます。

最上位に位置するのは、Modifierインターフェースです。Modifierには、all、any、foldIn、foldOutといったModifierチェーンを実現するためのメソッドが定義されています。
Modifierを継承しているのが、Modifier.Elementインターフェースです。Modifier.ElementはModifierチェーンを構成する個々の要素で、all、any、foldIn、foldOutのデフォルト実装を提供しています。(Kotlinのインターフェースって、メソッドの実装を書けるんですね。)
そして、Modifier.Elementの実装(の一つ)が、ModifierNodeElementです。ただしこれは抽象クラスなので、実際に使う時はModifierNodeElementをさらに継承したクラスを作ることになります。Modifier.Node対応済みのModifier修飾子(Modifier.fillMaxSizeやModifier.clickableなど)は、ModifierNodeElementのサブクラスのオブジェクトを返します。ModifierNodeElementは間接的にModifierインターフェースを実装しているので、Modifierチェーンの要素になることができるのです。
ModifierNodeElementと1対1で対応するのが、Modifier.Nodeです。Modifier.Nodeも抽象クラスなので、実際にはこのサブクラスを作成して使います。ModifierNodeElement.create()がModifier.Nodeオブジェクトを作成します。作成されたModifier.Nodeが、Layout関数でUIに適用されます。Modifier.NodeのonAttachやonDetachは、Layoutの処理に関連して呼び出されます。
Modifier.Elementにupdateメソッドが定義されているのがポイントで、Modifier.Node対応がパフォーマンス改善につながる所以です。UIの状態が更新されたとき、ModifierNodeElementはupdateメソッドでModifier.Nodeを更新します。長々としたModifierチェーンを一から構成しなおすのではなく、変更があった部分だけを更新することでパフォーマンスを改善しています(だと思います)。
Modifier.Nodeは、DelegatableNodeインターフェースを実装しています。delegateは「委譲する、まかせる」という意味で、DelegatableNodeは「まかせられる側」です。Modifier.NodeがDelegatableNodeを実装しているので、あるModifier.Nodeから別のModifier.Nodeに処理を任せることができます。これによって、既存のModifier.Nodeを組み合わせて複雑なModifierを実装することができます。
以上、今回はModifier.NodeとModifier.Elementを中心に、その周辺のインターフェースやクラスの関係性について整理しました。今後、具体的な実装例なども紹介できればいいなと思っています。