カテゴリー: Android

Kotlinでクラスのネストについて

はじめに

こんにちは。引き続きKotlinの基本文法で、今回はクラスのネストについてです。
JavaやSwiftにもある文法ですが、やはりよく理解せずに何となく使っていましたので、改めてきちんと理解したいと思います。

クラスのネスト

以下のコードはtry kotlinで試しています。クラスの中に新しいクラスを記述すればよく、特に難しいことはないと思います。

なお入れ子の階層に制限は無く、いくつでもネスト可能です。やり過ぎても可読性を落とすだけでしょうが…

fun main(args: Array) {
    println(Sample.Nested().msg)
    println(Sample.Nested.MoreNested().msg)
}

class Sample() {
    class Nested() {
        val msg: String = "nested class is running."
        class MoreNested() {
            val msg: String = "more nested class is running."
        }
    }
}

入れ子のクラスNestedMoreNestedptivateを付ければ、Sampleクラスからのみアクセス可能になります。

内部クラス

Kotlinではinnerキーワードを付けることで、内部クラスから外側のクラスのメンバーにアクセスできるようになります。
Androidではイベントリスナーの実装によく用いられています。下記コードではボタンクリック時と長押し時の処理を実装していますが、一つのイベントリスナーにつき一つの内部クラスとして処理が切り分けられており、リスナーが増えた場合でも可読性を保ちやすくなっています。
また、リスナーの中からMainActivity.messageを直接参照できるのもいいですね。
(AndroidStudio3.2.1, Kotlin1.2.71)

class MainActivity : AppCompatActivity() {
    lateinit var message:String

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button:Button = findViewById(R.id.button)
        button.setOnClickListener(ButtonClickListener())
        button.setOnLongClickListener(ButtonLongClickListener())
    }

    private inner class ButtonClickListener: View.OnClickListener {
        override fun onClick(v: View?) {
            message = "ボタン id:${R.id.button} が押されました"
            Toast.makeText(applicationContext, message, Toast.LENGTH_LONG).show()
        }
    }

    private inner class ButtonLongClickListener: View.OnLongClickListener {
        override fun onLongClick(v: View?): Boolean {
            message = "ボタン id:${R.id.button} が長押しされました"
            Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT).show()
            return true // falseを返すとOnLongClickListenerの後にOnClickListenerも呼ばれる
        }
    }
}

レイアウトのXMLは以下の通りです(ボタンを1個置いているだけですが…)。


  • 2行目のlateinitは前回の記事で紹介しました。このように、インスタンス生成時より後にプロパティを定義しつつ、最初からnon-nullで書けて便利です。
  • private修飾子を付けることで、MainActivityからのみ呼ばれることが明示されています。コードの読み手にも実装の意図が伝わりやすくなりそうです。

Javaコードとの比較

Javaで同様の実装をすると、以下のようになります。
1個のボタンに2つのリスナーを実装する程度では複雑にならず、読みづらくもありません。
ただ、さらに多くのイベントリスナーや他の処理が加わると、onCreateが肥大化していってしまうため、MainActivityにOnClickListenerインターフェースを実装するなどして、処理を切り分ける必要がありそうです。

public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button mButton = findViewById(R.id.button);
        mButton.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                String message = "ボタン id:"+R.id.button+"が押されました";
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
            }
        });
        mButton.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View mView) {
                String message = "ボタン id:"+R.id.button+"が長押しされました";
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
                return false;
            }
        });
    }
}

さいごに

いかがでしたでしょうか。今回例示したイベントリスナーの実装方法は他にもありますが、内部クラスを使った書き方は処理の切り分けがコードを一見しただけで判別しやすく、読み手に優しいコードを維持しやすいと感じました。

おすすめ書籍

nomura

シェア
執筆者:
nomura
タグ: KotlinAndroid

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

3週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前