【有料級】プログラマーから講師へキャリアアップ!講師指導者がタイムテーブルで教えるJava講義のポイント

Table of Content

この記事を読んでくれた全ての現役エンジニアが、IT講師になるハードルを下げられることを願って筆を執ります。
これからエンジニアになろうと思っている方も、こういう事があるんだと知っておいてもらえるとスクール選びで失敗しにくくなります。

想定読者(聴衆)

  • JavaやC系、Pythonなど(その多言語含む)でオブジェクト指向プログラミングをやったことがある
  • プログラミングにおける「クラス」を理解している、もしくは理解してないけど使える方(スクール受講生相当)
  • 以下の用語を聞いたことがある(知らない)
    • カプセル化(隠蔽化)
    • 継承
    • ポリモーフィズム(多態性)

現在、新卒IT研修の多くがJava案件なので、Javaで説明します。
(正直、最近の流行やキャリアの将来性を考えてPythonでもいいんじゃないかと思うわけですが、依然としてJavaが多いですね)

講義の心得

はじめて講師として教壇に立つなら、やっぱり気になるところですね。
講師研修の時には(それぞれの講師の個性を発揮してほしいので)指導しないのですが、今回は講師未経験者を対象にしているので、参考という事で困った時などに取り入れてみてください。

解説!オブジェクト指向(Java: 全15〜20分を想定))

実際に講義を想定しますので、各章に目安時間を設けます。
模擬講義では聴衆もいなければリアクションもないため、逆にやりにくいと感じることがありますが、必ず質問をしてこない受講生だと考えて、淡々と進めていきましょう。
ある程度講師経験があるなら、問いかけを入れても良いでしょう。

オブジェクト指向はほぼ100%「分からない事が分からないので質問がありません(できません)」という受講生が出る単元なので、クラスを複数作る時とかDB接続する時(JDBCなど)で説明するとイメージしやすい傾向にあります。
先にオブジェクト指向について概念を説明しておいて「後でまた出てくるので、その時にも改めて解説しますね」としておくと、安心感があって良いです。

以下、時間配分込みで意識していることです。
この単元のポイントは「後でもう一度やるので、手続き型以外の書き方がある」事を体感してもらうことです。

※※ただし「実務でどうやって使っているか」を営業ご担当者よりヒアリングしている場合は「実務ではやらないけど地力を高める」or「実務に合わせた研修プランをカスタマイズしている」のか、事前に確認しておきましょう。
大事なポイントなので、後述します。

オブジェクト指向とは(板書込み5分)

「そもそもオブジェクトってなんやねん🤔」という話から。
オブジェクトは「モノ」です。プログラムでモノを作ろうという考え方がオブジェクト思考です。

オブジェクト(モノ)がもたらすもの(1分)

多くのテキストが「オブジェクトは状態と機能を持つ」と書いています。
状態とは?機能とは? こんな抽象的な書き方をされてもよく分かりません。
教える側(あなた)も分かりにくいと感じたら、教わる側(将来の受講生たち)はもっと分かりません。
講師の仕事は「このよく分からないものを受講生目線で見える(イメージできる)もの」に翻訳することです。

これをふまえて、オブジェクトの状態や機能をどう説明するか考えます。

フィールド=オブジェクトの状態(1分)

専門用語で「フィールド」と呼ばれる「オブジェクトの状態」ですが、フィールドとは?
率直に言うと「オブジェクトが保持する変数」です。
プログラミングを漠然と勉強し始めた方=手続き型プログラミングをやっている人は、変数がフィールド、オブジェクトの状態だと考えてもらってOKです。
変数には何かが入っています。数値だったり文字列だったり、あるいは関数だったり。
ここでは変数に関数を入れるケースは難しいので除外しますが、変数を参照すると何かしら代入されている内容を取得できます。
フィールドも同じです。

概念的な話に戻ります。
オブジェクトの状態とは、オブジェクトが今どうなってるのかを知る方法と言えます。
「変数の中に何が入っていますか?」と質問した時に「取得した値=これはなんでもいいです」が入っていると言えればフィールドの理解は完了です。

メソッド=オブジェクトの機能(1分)

専門用語で「メソッド」と呼ばれる「オブジェクトの機能」ですが、メソッドとは?
率直に言うと「オブジェクトが実行する関数」です。
多くのプログラミング言語でいうと、命令を書いた後に()を書きますが、このカッコがついているものが実行を意味します。
今までJavaで学んだところでいえば、printf("Hello world!")が該当します。
(必ずしもこのルールに当てはまらない言語もありますが、Javaの場合はほぼこのルールに当てはまるため、力がつくまではこの理解する事を推奨します)

プログラミングを始めて少し経つと、自作関数とかサブルーチンという言葉を覚え、使い始めるようになると思います。
その時に「オリジナル()」みたいな宣言をすると思います。
このオリジナルは何でもいいです。

オブジェクト指向とJava(板書込み2分)

Javaを実行する時はこんな感じに書きます。

// Hogeクラスの宣言
public class Hoge {

  // Hogeクラス内のmainメソッド
  public static void main(String[] args) {
    // 実行処理
  }
}
  • public class Hogeがクラス
  • public static void main(String[] args)がクラス内関数(=クラス内メソッド)

と、読み替えることができます。
Javaではオブジェクトの事をクラスと呼びます(厳密には違いますが、理解が浅いうちは問題ありません)ので、クラスを作る=オブジェクトを作るという理解でよいです。
publicは今は無視してよいので、class句でオブジェクトを作ったんだなと考えてもらうようにしてください。
次に着目するのが「クラスの中にmain(String[] args)とメソッドを書いている」というルールを認識してもらう事です。
ここではmain()に注目してもらい、String[] argsはいったん無視してもらいましょう。
板書で図解するように解説すると効果が高いです。

忘れがちなルール

Javaはメソッドを書く時は必ずクラス内に書く必要があります。
クラス→メソッドの順です。
メソッド内でクラスを定義する事はできません。

手続き型指向からオブジェクト指向へのパラダイムシフト(板書込み5分)

オブジェクト指向で作るメリットは「手続き型で作った変数と、関数を同時に管理しやすい事にある」と思います。
厳密に言うと色々ありますが、よくわからないうちはこのレベルの理解でいいと思います。

たとえば「変数A_位置」と「変数B_位置」を管理したいケースがあると想定します。
作成する変数としては、

  • 変数A
    • x座標
    • y座標
    • z座標
  • 変数B
    • x座標
    • y座標
    • z座標

のようなものが必要になります。
配列で頑張るとこんな感じでしょうか。

// クラス名、関数名宣言は省略
float[] varA = {1, 2, 3}
float[] varB = {4, 5, 6}

配列にはx,y,zの順番で値を格納したので、必要なタイミングで配列の要素を指定すれば良いです。楽ちんですね。
では、一ヶ月近くこのプログラムを寝かせた状態で、また振り返ってみたとします。
配列の1番目の要素に何が入っているか分かりますか?
たとえば、printf(varA[0])とやれば、x座標の数値(1)が入っているので何かしらの値は入っているな、と確認できると思います。
では、verA[0]が何を意味するのか、一ヶ月後に振り返って思い出せるか?という話です。
配列の要素に名前をつけたくなりませんか?

そこで、クラスの出番です。
同じようにやってみましょう。

class Position {
  float x;
  float y;
  float z;
}

とクラスを作っておいて、メイン関数で

// クラス名、関数名宣言は省略
Position varA = new Position();
varA.x = 1
varA.y = 2
varA.z = 3

Position varB = new Position();
varB.x = 4
varB.y = 5
varB.z = 6

と書くと、配列ではなくなったので呼び出し方もprintf(varA.x)のように書きかわります。
配列の時と違って、varA[0]ではないので、なんとなく推測できますね。

これを配列で解決する場合は、以下のようなアプローチがあります。

// クラス名、関数名宣言は省略
int x = 0;
int y = 1;
int z = 2;
printf(varA[x]);

とする方法もなくはないです。
が、今回は分かりやすいから何とかなりそうですが、クラスがいっぱいできたら全部管理できるか?というとそうでもないですよね。
こういった面から、複雑なプログラムは手続き型からオブジェクト型に変えていった方が管理をしやすくなるという面があります。

もちろん、メリットはこれだけではありません。

オブジェクト指向を学ぶ理由(5分)

この単元は引っ張ってはいけません
大事なところなので、じっくり解説したくなりますが内容を理解していないうちに詰め込みすぎると苦手意識を植え付けてしまう事になりかねません。

この単元のポイントは

  • カプセル化:変数を参照できたり、参照できなかったりさせる
  • 継承:スーパークラスの内容を使いまわしできる →共通の処理を持つクラスを作るのが楽になる
  • 多態性:継承した内容を上書きできる →呼び出す側がサブクラスの内容を知らなくても良い

上記3つを理解してもらうことです。
ここでは5分を目安としていますが、質問も多い単元なので、これらにはしっかりと回答しましょう。
質問者は理解しかかっていて、他の受講生は質問の内容を理解できていない状態にあるので、時間配分や対応方法は意識しておきましょう。
補足部分は初回の解説ではやらないようにすることをおすすめします。

カプセル化

オブジェクト指向を使うと、プログラムの安全性や拡張性が高まるのが大きなメリットです。
「カプセル化」と言ったりします。

先ほどの例で言うと、

Position varA = new Position();
printf(varA.x);  // 1が表示される

この「1が表示される」の部分をエラーにする事ができます。
なぜエラーにするのかというと、許可した場所以外で表示されると困る情報を保護したい場合があります。
実務で使いやすいのは、「表示は許可するが変更は許可しない」場合です。
こういった細かな制御ができるのもカプセル化のメリットです。

継承

継承は、クラスの内容を引き継いで新たなクラスを定義できることです。
引き継ぐ元のクラスをスーパークラス(親クラス)、引き継いだ先のクラスをサブクラス(子クラス)と呼ぶ事もあります。

現実に準えると、人間の祖先は猿だと言われますが、猿も跳べますし人間も跳べるのです。

たとえば、プログラムを書いていると、似たような処理を書く機会が多くなります。
機能(メソッド)Aと機能Bで同じ事をやるなら、どちらかにまとめてしまった方が、メンテナンスが楽になります。
2箇所に同じ処理を書いていたものを、一箇所にまとめて呼び出すようにすると、変更点もまとめた部分だけやると一括で変換できます。

また、フィールドを引き継ぐ事もできます。
誤解を恐れずにいうと、クラスをコピーして新しいクラスを定義する事を継承と考える事ができます。

補足:is-aとhas-a

共通処理を継承関係で持たせるべきか、あるいはフィールド等に持たせるべきかは設計の問題です。
新人研修では「クラスAにあるものを使う場合、以下の2通りの方法で使用することができます」とだけ伝えましょう。

まずは共通クラス

class Sample {
  // 解説のためpublicとしていますが、これは良くはないですね
  public string sampleFIeld = "A";
}

これをどうやって使うのか?というのを考えてもらうようにします。

// is-a
class B extends Sample{
}

// has-a
class B {
  Sample field = new Sample();
}

// メインメソッド内。細かいのを省略
print(new B().sampleField);  // is-a
print(new B().field.sampleField;  // has-a

↑のコードの違いを受講生が認識できれば、それ以上は踏み込むべきではないです。

先述しましたが「どちらが良い」という話はしないようにします。
良かれと思って個人の経験をお話する事もあると思いますが、実はこれがクライアントに迷惑が掛かったり(受講生が反感を持つことが考えられる)しますので、実務でどのように採用されているか注視するように促すのがベストだと思います。

ポリモーフィズム(多態性)

継承ではスーパークラスの内容を引き継ぎますが、一部機能(メソッド)だけはオリジナルにしたい事があります。
こういった場合は、スーパークラスのメソッドを書き換える事ができます。
(メソッドのオーバーライドといいます)

現実に準えると、また人間と猿の例ですが、食事をする際に猿は手で掴んで食べ物を口に運びます。
人間は箸やスプーン、フォークなどを使って食べ物を口に運びます。
パンやピザなど、直接手で掴む事もできます。
同じ「食事」という行動でも、このように行動パターンが異なるのです。

このように、同じ機能名でもスーパークラス(親クラス)と異なった振る舞いをさせる事ができます。
こういった機能をポリモーフィズム(多態性)と呼びます。

ポリモーフィズムの実践例としては、スーパークラスをコピーして作ったけど、特定のメソッドだけはオリジナル機能を使いたい場合に使います。
ただし、スーパークラスに存在しないメソッドを追加する事をオーバーライドとは言わないので注意が必要です。

補足:ポリモーフィズムと型変換の解説

テキストによってはアップキャスト・ダウンキャストを取り扱う事がありますが、ポリモーフィズムの解説と型変換はどちらも複雑でややこしい単元であるため、理解を促す際は切り離すべきです。
どちらも習得できてはじめて、組み合わせた話をしましょう。ここでこんがらがる受講生はきちんと理解できていない事がわかります。

ダウンキャストは気をつけてくださいね。

class Super {
  public string superField = "スーパークラス";
}
class Sub extends Super {
  public string subField = "サブクラス";
}

// メインメソッド
Sub sub = new Super();
printf(sub.subField);

これは失敗します。変数subのsubFieldが初期化されていないからですね。
(SuperにsubFieldが含まれておらずnewで初期化できないため)
メインメソッドにsub.subField = "メインメソッド"とか入れて初期化してあげましょう。

補足:なぜ新しいメソッドを作らず、既存のメソッドを上書き(オーバーライド)するのか?

呼び出し元で親クラスだけ知っていれば、振る舞いを気にしなくてよいからです。
たとえば、Aクラスを継承したBクラスを使用する場合、Aクラスの使い方を知っていればBクラスも同じフィールド・同じメソッドがある事を確実に担保できます。

これに対し、Bクラスに新しいメソッドを作った場合は、呼び出し元でも新しいメソッドの存在を把握しておく必要があるため、運用コストが高まります。
もっと極端に言うと、呼び出し元でAクラスのメソッドが何をやっているのか、細かく知る必要はありません。
同様に、Bクラスがオーバーライドしても、Aクラスのメソッド名で呼び出せると、実行しようとしている変数の型がAクラスなのかBクラスなのか気にする必要がないので運用が楽になります。

解説を読む程度ではイメージしにくいですが、「来月プログラムのメンテナンスをする」と考えた時、覚える量が少ない方がいいよね〜、ぐらいの感覚で良いです。

まとめ(1分)

オブジェクト指向を学ぶため、まずはオブジェクトとは何か?
今まで学んできた手続き型の書き方と、オブジェクト指向の書き方の違いの比較、
そして、オブジェクト指向を使うと何が嬉しいのか?

の3点について解説しました。

研修で説明する内容は小さいシステムばかりなので、オブジェクト指向の良さを体感しにくいかもしれません。
ただし、複数人で開発したり大きなシステム開発をする場合は、きちんとしたルール=オブジェクト指向での開発をしておいた方が、開発をルール化したり将来的にメンテナンスする際に読みやすくなる傾向があります。

ただし、何でもかんでもオブジェクト指向にすれば良いと言うわけではありません。
ちょっとしたプログラムなら、今まで学んできた手続き型で書いた方が楽だし、構造的にもシンプルなので読みやすい事も多いです。
開発の規模に合わせて使い分ける事が重要です。

講師向けコラム:ポリモーフィズムは難しい?(補足・全体で時間が余った場合)

Javaを座学で学ぶと、多くの人がハマるのがポリモーフィズムです。
私も、初学の頃は上記の疑問でハマってしまい、非常に苦労しました。

というのも、座学や研修で学ぶ時は、AクラスもBクラスも呼び出し元での実装も、全部一人でやるからです。
ポリモーフィズムを理解するには、みんなでAクラスを継承したBクラスを作り、思い思いの処理をオーバーライドしましょう。
ここでの「思い思いの処理」はなんでもいいです。
そして、みんなが作ったBクラスをインポートして実施してみましょう。
そうすると、一人一人違った処理をすることに気づくと思います。

このように、「誰が何をやったか分からないけど、呼び出し側のコードはクラス名を書き換える」だけでエラーにならず、処理を正常終了できる事が確認できると思います。
これがポリモーフィズムの真価です。

講義では教えない、オブジェクト指向のお話

多くのプログラミング系アフィリエイトサイトで間違った解説をしているのが散見されます。
参考サイトを探す際は、サイトの管理者がきちんとしたエンジニアか、あるいはエンジニアが監修したサイトであるかどうか確認してください。

参考情報:私のプロフィールページです。

https://wordpress.local/profile.html

シェアする