2017年度資料
テーマとキーワード: 振る舞いに関するパターン
Command, Iterator, Memento, (Strategy)
オブジェクト指向とクラス図(UML) 参照
デザインパターン GoFの提唱したデザインパターン。パターンのカタログ。良いコード作成のパターンに名前を付け、概念共有を促進した。
本講義では、生成に関するパターン、構造に関するパターン、振る舞いに関するパターン から幾つか代表的なものを取り上げ、Javaのプログラム課題として取り組む。
デザインパターン導入のメリット
・コード修正時のコードの複雑化を抑える。
if や for など制御構造や変数を駆使して個別のプログラムが必要な量が減る
・よく用いられているパターンを知ることでデザパタ導入のコードの可読性が増す。
・よく用いられているパターンをコードに導入することで、他のデザパタを使用したコードとスムーズに結合できる。※言語標準のライブラリーなど。
デザインパターン導入のデメリット
・クラスが増える
・クラス間の依存が増える
既存のコードの改良、もしくはコードを継続的に運用して修正・変更が加わることが導入の前提。
デザパタ導入で増えたコードによる複雑化以上のメリットがない場合もある。
・コードの動作を捉えにくい
どのデザパタを使っているか知らないと、導入したクラスの役割や効果を理解しにくい。
関数型プログラミング と オブジェクト指向
関数型のプログラミング言語や、それ由来の言語使用を導入したモダンなプログラム言語では、デザインパターンのうち幾つかは特に意識しなくても自然にコードを作成できるようになっている。
型推論や関数(クロージャ)を使用したプログラミングについて、第12回、第13回で軽く触れる予定。
Cat クラスにCommandパターンを導入し、猫の行動の具体的な内容を Commandオブジェクト に委譲する。
Cat クラスにMementoパターンを導入し、猫の行動に Undo 機能を実装する。
参考 Command と Memento パターンを利用した お絵かきアプレットの例)
2013年応用プログラミングI(旧カリキュラム)提出課題1311092
当初予定: 生成に関するパターン Singleton, Factory Method, Abstract Factory
オブジェクト指向やめましょう http://www.slideshare.net/nowokay/ss-41730024
紹介:
Visitorパターンで遊んでみたよ http://codezine.jp/article/detail/6829
GoFのデザインパターンについて、短文で要点解説、参考資料への豊富なリンクあり GoFの23のデザインパターンを,Javaで活用するための一覧表 (パターンごとの要約コメント付き)
演習
Javaプロジェクト java5 を新規作成する。
このページに添付してあるファイル L10.java をダウンロードして、src フォルダにドラッグ&ドロップでコピーする。
デフォルトパッケージの L10.java を開いて、以下の内容で編集していく。
・Debug
実行の構成を設定して、 L10を Java アプレット として実行 する。
コンソールに実行結果の文章が表示される。
キャラクターの 名前 と 使用したアイテムの名前 が表示されるが、名前が null と表示されるバグを修正する。
(ヒント)
・オブジェクトの初期化(インスタンス生成)にバグが潜んでいるので、class Cat のコンストラクタを確認
・コードを読んで、動作を追いかけながら、
コンストラクタ
コンストラクタのチェーン
インスタンスのフィールドへのアクセス
抽象クラス
抽象メソッド
インターフェース
インターフェースの実装
のJavaの文法と機能について確かめる。
・クラスの追加とデザインパターンの適用
Command パターン と Memento パターンにより、猫クラスにコマンドの実行と、行動リストの解決、行動手順のUndo のの機能を実装する。
Mementoパターンで、コマンドの実行状況を記録する MacroCommand の例)
//Commandのインターフェース
interface Command {
public abstract void execute();
}
//連続コマンド用のMacroCommandのクラス
class MacroCommand implements Command {
private Stack<Command> commands = new Stack<Command>();
public void execute() {
for(Command cmd:commands) {
cmd.execute();
}
}
public void append(Command cmd) {
commands.push(cmd);
}
public void undo() {
if (!commands.empty()) {
commands.pop();
}
}
public void clear() {
commands.clear();
}
}
Java の Stack クラスを利用している。
スタックのメソッド:
データを入れる push
データを取り出す pop
データの取り出しでは、常に最後に入れたデータが取り出される。
お菓子の ペッツ の容器の様に) http://japanpez.blogspot.jp/2012/01/4-pez.html
ハンドガンの弾倉の構造も似ていいる。 http://ja.wikipedia.org/wiki/%E5%BC%BE%E5%80%89
各コマンドの作成
例) Item を使用するコマンド
class UseItemCommand implements Command {
ItemOwner io;
public UseItemCommand(ItemOwner io) {
this.io = io;
}
public void execute() {
io.useItem();
}
}
コマンドの実行タイミングの変更:
マルチスレッドにより画面描画とは別のスレッドでコマンドを実行するようにL10.java を変更。
public class L10 extends Applet implements Runnable{
private MacroCommand history = new MacroCommand();
run メソッドを追加(コード修正機能)。ここでコマンドを実行するように、paintからコードを移動。
@Override
public void run() {
history.execute();
}
start メソッドを追加。(右クリック→ソース→メソッドのオーバーライド)
public void start() {
super.start();
(new Thread(this)).start();
}
2017年度の課題
・抽象クラス Item や Animal のサブクラスとして具象クラスを幾つか class定義する。
クラス名は、適当にそれらしい名前を各自で指定してよい。
・既存のクラスや新規に定義したクラスを使用して、コンソール上で動作確認をするためのコードを
init() メソッドに追加する。
例)
猫を複数作成し、個別に名前をつける。
音が出るアイテムを幾つか作成し、猫に持たせる。
猫に幾つかのコマンドを実行させる。
猫に複数のアイテムを持たせてもよい。
作成例のコードを L10作業例.java として、このページに添付しておく。
以下、2016年度の演習内容
2017年度はパスする。
Cat クラスを修正する:
class Cat extends Animal implements ItemOwner {
String item;
int x;
int y;
Image img;
Dir dir;
enum Dir {UP, DOWN, RIGHT, LEFT};
Cat のメソッド修正:
Cat(String name,Image img) {
super(name, Size.Small);
this.img = img;
dir = Dir.UP;
}
void walk(int step) {
// ねこが step 歩く
System.out.println(getName() + "が" + step + "歩移動" + dir.toString() + "方向に。");
switch(dir) {
case UP:
y -= step;
break;
case DOWN:
y += step;
break;
case RIGHT:
x += step;
break;
case LEFT:
x -= step;
}
}
コマンドのタイプを追加する:
class WalkCommand implements Command {
Cat cat;
public WalkCommand(Cat cat) {
this.cat = cat;
}
public void execute() {
cat.walk(10);
repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class UpCommand implements Command {
Cat cat;
public UpCommand(Cat cat) {
this.cat = cat;
}
public void execute() {
cat.dir =Cat.Dir.UP;
}
}
その他のコマンドの作成は、受講生に任せる。
画面内に、キャラクターが描画されるようにする。
キャラクターの登録場所の準備:
private Stack<Cat> catstack = new Stack<Cat>();
キャラクターの登録例:
Cat mycat = new Cat("引っ越し",img);
catstack.push(mycat);
Cat mycat2 = new Cat("引っ越し2",img);
catstack.push(mycat2);
※ Catは catstack につまれている場合に画面に描画されるものとする。
キャラクター画像の読み込み例:
Image img;
img = getImage(getCodeBase(), "kohashi.jpg");
ペイントメソッドに、catstacckの猫を描画するコードを追加する。
public void paint(Graphics g) {
offg.setColor(Color.white);
offg.fillRect(0, 0, 600, 600); // 画面を消去する
for(Cat cat:catstack) {
offg.drawImage(cat.img, cat.x, cat.y, 50, 100, this);
}
g.drawImage(offimg, 0, 0, this); // オフスクリーンを描画
}
init メソッド内で新しく定義したコマンドを使用して、Cat に行動させる。
例)
右斜め下に、階段状に移動し、最後にアイテムを使用する。
Command cmd1 = new UseItemCommand(mycat);
Command cmdR = new RightCommand(mycat);
Command cmdW = new WalkCommand(mycat);
Command cmdU = new UpCommand(mycat);
Command cmdD = new DownCommand(mycat);
for(int i=0;i<10;i++) {
history.append(cmdR);
history.append(cmdW);
history.append(cmdD);
history.append(cmdW);
}
history.append(cmd1);
課題:
画面内に猫を複数登録し、それぞれ別々の行動を取らせる。