オブジェクト指向 プログラミング演習sun.ac.jp/prof/yamagu/2019OOP/OOP11.pdf ·...
Transcript of オブジェクト指向 プログラミング演習sun.ac.jp/prof/yamagu/2019OOP/OOP11.pdf ·...
オブジェクト指向プログラミング演習
第11回 リファクタリング・抽象クラス・ポリモルフィズム
2019.06.27
リファクタリング
プログラムを、外部への動作を変えずに、書き変えること
⚫ プログラムを整理する
◆バグが存在する可能性を減らす
◼より分かりやすく
◼より短く
◆自分が書いたプログラムを納得できるように
◼納得したコードしか書いていない人は良いのですが…
◼他のものを作るときに再利用しやすいように
※)多少変わってもよい。ゆるく考えましょう
2019.06.27
refactoring
※
性能が改善されない書き変えもする
2019.06.27
プログラムを整理するとは?
⚫ 何をしているか、を人間(自分・他人)にとって読み取りやすくする
◆ クラスやメソッドの役割(機能)を明確にする
◆ 同じモノには同じ名前をつける
例)Controlが参照するModelとViewが参照するModelには同じフィールド名をつける
◆ 個々のメソッドの中身の行数を少なくする
◆ 複雑な手順は意味ごとにメソッドにして分ける
◼ メソッドには中身を表すちょうどよい名前をつける
◆ 定数に名前をつける(final static なフィールドを宣言する)
⚫ 似たコードを何度も書かない
◆ 繰り返しで書ける手順は繰り返しを使う
◼ 計算できる値は、式を書いて計算させる
◆ 同じ意味の手順をメソッドにして、それを呼ぶ
◼ 細かな違いは引数を変えることで対応する
⚫ データのやり取りをできるだけ簡素にする
◆ 他クラスのインスタンスのフィールド参照を減らす
◼ クラスの設計を見直す
リファクタリングのやり方
⚫ フルスクラッチ
ソースコードを最初から全部書き直す
…既存のコードがぐちゃぐちゃで、なぜ動くのか書いた本人にもよく分からないときに有効
⚫ 既存コードを眺めて、気づいた点を少しずつ整理する 2019.06.27
リファクタリングでない場合にも、既存コードを一切流用しない開発をフルスクラッチと呼ぶ(和製英語)
この中間
⚫ モジュールごとに、書き直したり、改造したり
⚫ モジュール化をやり直して、中身は既存コードの流用
リファクタリングの具体例①
gc.drawLine(30,30,30,570);
gc.drawLine(90,30,90,570);
gc.drawLine(150,30,150,570);
gc.drawLine(210,30,210,570);
gc.drawLine(270,30,270,570);
gc.drawLine(330,30,330,570);
gc.drawLine(390,30,390,570);
gc.drawLine(450,30,450,570);
gc.drawLine(510,30,510,570);
gc.drawLine(570,30,570,570);
gc.drawLine(30,30,570,30);
gc.drawLine(30,90,570,90);
gc.drawLine(30,150,570,150);
gc.drawLine(30,210,570,210);
gc.drawLine(30,270,570,270);
gc.drawLine(30,330,570,330);
gc.drawLine(30,390,570,390);
2019.06.27
for(int i=0 ; i<=9 ; i++) {
int s=30+i*60;
gc.drawLine(s,30,s,570);
gc.drawLine(30,s,570,s);
}
似たコードを何回も書いている。いずれも「盤面の線を引く」という同じ意味のことをやっている。
繰り返しを使って短く
書く
リファクタリングの具体例②
2019.06.27
if (board[x][y] == -1) {
…
}
if (board[x][y] == Empty) {
…
}
クラスのどこか(たとえば始めの方)で、final static int Empty = -1;
と宣言しておく。
board[x][y]が「空きマス」だったら、…という意味が明確になる。
2019.06.27
インデント(字下げ)や改行
プログラムを読みやすくするために重要
ソースコードの字下げや改行についてポリシーを決め、それに従って書き直すこともリファクタリングの一つ
例)
⚫ プログラムの構造(中括弧)の入れ子ごとに何文字の字下げをするか?(山口は2文字派)
⚫ { の前で改行するか?(山口はしない派)
⚫ ifやforで実行すべき内容が1文のとき、{}に入れるか?(山口は、その1文の長さに依る派)
2019.06.27
最終課題
提出したプログラムを、改造・機能拡張・リファクタリングし、完成したプログラムについてレポートを書き提出しなさい。
⚫ ゲーム/パズルのルールを逸脱してはならない
締め切り:2019年7月31日17:00
⚫ ゲーム/パズルとして未完成な者は当然完成させる
⚫ リファクタリングしてからの方が機能拡張しやすい
⚫ 機能拡張の例:◆ UIにアニメーションや効果音を導入
◆パズルの問題を複数から選択できるようにする
◆ 1端末で対戦していたゲームをネットワーク対戦にする
◆パズルの(人による選択が不要な)一部を自動化
最終課題にむけて
以降の授業では、リファクタリングに使えそうな技術を紹介する:
◆抽象クラス
◆ポリモルフィズム
◆デザインパターン
◆コメント
◆Package
◆API
2019.06.27
今日の後半の内容
次回(第12回)の内容
次々回(第13回)の内容
抽象クラス
実体を持たない(インスタンスを作らない)クラスを定義することもできる。これを抽象クラスと呼ぶ。
(このクラスを継承するクラスがインスタンスを持つ)
⚫ 抽象クラスを継承するクラスが実装しなければならないメソッドの型を宣言できる…インタフェースに似ている
⚫ フィールドやメソッド(メソッドの中身も)を定義できる
2019.06.27
抽象クラスの定義の仕方
abstract class クラス名 {
フィールドやメソッド
abstract 返戻値の型 メソッド名(仮引数, ...);
}
2019.06.27
クラス宣言の前に abstract
というキーワードを付ける
フィールドやメソッドを書けるのは、普通のクラスと同じ
インタフェースと同様に、メソッドの型だけ宣言することもできる。その場合は、abstract というキーワードを付ける
実体を持たない「モノの種類」
インタフェースや抽象クラスは、それ自身のインスタンスを持たない。
…インタフェースを実装したクラス・抽象クラスを継承したクラスがインスタンスを持つ。
個々のインスタンスはそれぞれ別の下位概念(クラス)に属していて、全体として共通する性質を表現したいときなどに使う。
2019.06.27
ク ラ ス
ポリモルフィズム
同じ名前で異なる型の引数を受け取るメソッドを複数定義できる
⚫名前が同じでも、引数の型が違えば、違うメソッドとして扱われる
⚫呼び出すときの引数によって異なるメソッドを呼び出せる
※仮引数の型が異ならなければならない。仮引数名が違っても型が同じであれば、二重定義(エラー)またはオーバーライドになる 2019.06.27
ポリモルフィズムの使い方
メソッドの名前は機能を表す
⚫ その機能に必要な引数の渡し方に何通りもある時
例)java.awt.GraphicsクラスのdrawImageメソッド:
いずれも画像を表示するメソッド。
大きさを変えたり、画像の一部を表示する機能がある
◆本質的には同じ機能だが、引数に複数の表現の仕方がある場合
◆引数のいくつかを省略できる場合
※ ポリモルフィズムを使って複数のメソッドを定義する場合、実際的な作業を行うメソッドとしては、より一般的な少数のメソッドを定義し、その一般的なメソッドを呼ぶだけの(引数の型が異なる)メソッドを定義することが多い。 2019.06.27
プログラムの性能改善の例
やらなくてよい計算は、できるだけやらない
⚫繰り返しの中で、本当に繰り返す必要のある計算だけをする
⚫あらかじめ計算して記憶しておける場合は、一度おこなった計算結果を使いまわす◆意味がある値には名前(変数名・フィールド名)を付ける
2019.06.27
Javaプログラムの性能改善の例
new の実行回数をできるだけ減らす
例)Color や Font を paint メソッド内でnew するのは無駄
… paint はGUIスレッドが何度も呼ぶ
→明示的に繰り返すコードにはなっていないが繰り返される
◆同じ色、同じフォントを毎回 new するのは無駄
➡ Canvasのサブクラスに使う色やフォントのフィールドを用意し、コンストラクタでnewして、使いまわす。 2019.06.27
次回予告
⚫デザインパターン
⚫コメント
2019.06.27