お知らせ

Similar documents
Microsoft PowerPoint ppt

JavaプログラミングⅠ

プログラミング基礎I(再)

Microsoft PowerPoint - chap10_OOP.ppt

Prog1_15th

た場合クラスを用いて 以下のように書くことが出来る ( 教科書 p.270) プログラム例 2( ソースファイル名 :Chap08/AccountTester.java) // 銀行口座クラスとそれをテストするクラス第 1 版 // 銀行口座クラス class Account String name

Microsoft PowerPoint - prog03.ppt

ただし 無作為にスレッドを複数実行すると 結果不正やデッドロックが起きる可能性がある 複数のスレッド ( マルチスレッド ) を安全に実行する ( スレッドセーフにする ) ためには 同期処理を用いるこ とが必要になる 同期処理は 予約語 synchronized で行うことができる ここでは sy

Javaプログラムの実行手順

Microsoft PowerPoint Java基本技術PrintOut.ppt [互換モード]

Microsoft PowerPoint - Pro110111

人工知能入門

JavaプログラミングⅠ

Java 基礎問題ドリル ~ メソッドを理解する ~ 次のプログラムコードに 各設問の条件にあうメソッドを追加しなさい その後 そのメソッドが正しく動作することを検証するためのプログラムコードを main メソッドの中に追加しなさい public class Practice { // ここに各設問

メソッドのまとめ

PowerPoint プレゼンテーション

JavaプログラミングⅠ

** 平成 16 年度 FE 午後問題 Java** 示現塾プロジェクトマネージャ テクニカルエンジニア ( ネットワーク ) など各種セミナーを開催中!! 開催日 受講料 カリキュラム等 詳しくは 今すぐアクセス!! 平成 16

Microsoft PowerPoint - prog04.ppt

Java知識テスト問題

JavaプログラミングⅠ

JAVA とテンプレート

JAVA入門

Javaセキュアコーディングセミナー2013東京第1回 演習の解説

文字列操作と正規表現

Microsoft PowerPoint - prog09.ppt

Microsoft PowerPoint - prog09.ppt

Java講座

.NETプログラマー早期育成ドリル ~VB編 付録 文法早見表~

IT プロジェクト

JAVA入門

2

プログラミング入門1

デザインパターン第一章「生成《

GEC-Java

メディプロ1 Javaプログラミング補足資料.ppt

Javaの作成の前に

11 ソフトウェア工学 Software Engineering デザインパターン DESIGN PATTERNS デザインパターンとは? デザインパターン 過去のソフトウェア設計者が生み出したオブジェクト指向設計に関して, ノウハウを蓄積し 名前をつけ 再利用しやすいようにカタログ化したもの 各デ

PowerPoint プレゼンテーション

問題1 以下に示すプログラムは、次の処理をするプログラムである

Javaセキュアコーディングセミナー東京 第2回 数値データの取扱いと入力値の検証 演習解説

ガイダンス

JAVA入門

ガイダンス

Make the Future Java FY13 PPT Template

Sort-of-List-Map(A)

GEC-Java

基本情報STEP UP演習Java対策

PowerPoint Presentation

PowerPoint プレゼンテーション

解答上の注意 1 解答は 解答 紙の問題番号に対応した解答欄にマークしなさい 2 選択肢は 問ごとに 意されています 問 1の選択肢は 問 2で使 しません 3 選択肢は量が多いため 探しやすさの観点よりグループ分けされています グループ分けに合わせて解答欄が区切られていますが 横 1 列で問題 1

問 次の Fortran プログラムの説明及びプログラムを読んで、設問に答えよ。

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

Microsoft PowerPoint - lec06 [互換モード]

Prog2_12th

プログラミング入門1

Microsoft Word - C言語研修 C++編 3.doc

Brekeke PBX - Version 2.1 ARSプラグイン開発ガイド

PowerPoint プレゼンテーション

JavaプログラミングⅠ

Prog1_6th

リファレンス,配列 例外処理

108 頁通過テスト 2. の本文 111 頁紹介文 136 頁練習 5-1 プログラム 136 頁練習 5-1 問 2 末尾に句点追加 158 頁練習問題文 161 頁練習 2-2 コメント文 166 頁練習 3-1 問 1 クラス名を挿入 178 頁通過テスト 3 文字 s を削除 180 頁コ

プログラミング入門1

デジタル表現論・第4回

Exam : 1z1-809-JPN Title : Java SE 8 Programmer II Vendor : Oracle Version : DEMO Get Latest & Valid 1z1-809-JPN Exam's Question and Answers 1 from Ac

第 3 回 Java 講座 今回の内容 今週の Java 講座はコレクション 拡張 for 文, ガベージコレクションについて扱う. 今週の Java 講座は一番内容が薄いも のになるだろう. コレクション コレクションとは大きさが決まっていない配列だと考えればよい. コレクションには List 先

ALG ppt

Prog1_10th

Microsoft PowerPoint - ●SWIM_ _INET掲載用.pptx

Week 1 理解度確認クイズ解答 解説 問題 1 (4 2 点 =8 点 ) 以下の各問いに答えよ 問題 bit 版の Windows8.1 に Java をインストールする時 必要なパッケージはどれか 但し Java のコンパイルができる環境をインストールするものとする 1. jdk

intra-mart Accel Platform — イベントナビゲータ 開発ガイド   初版   None

untitled

できるプログラマーを本気で育てる Java 超 Webプログラマーへの第 歩 第 2 回オブジェクト指向 テクノロジックアート 瀬 嘉秀

Microsoft Word - NonGenList.doc

ガイダンス

第1章 ビジュアルプログラミング入門

Method(C 言語では関数と呼ぶ ) メソッドを使うと 処理を纏めて管理することができる 処理 ( メソッド ) の再実行 ( 再利用 ) が簡単にできる y 元々はC 言語の関数であり 入力値に対する値を 定義するもの 数学では F(x) = 2x + 1 など F(x)=2x+1 入力値 (

Microsoft Word - NonGenTree.doc

Microsoft PowerPoint - prog08.ppt

Prog2_9th

とても使いやすい Boost の serialization

PowerPoint プレゼンテーション

1.SqlCtl クラスリファレンス SqlCtl クラスのリファレンスを以下に示します メソッドの実行中にエラーが発生した場合は標準エラー出力にメッセージを出力します (1)Connect() メソッド データベースへ connect 要求を行います boolean Connect(String

JavaプログラミングⅠ

メソッドのまとめ

1. はじめに 二分木ヒープ 様々なアルゴリズムにおいて ある要素の集合またはリストから 最小 な要素を取り 出す必要がある そのような場合に使われる標準的データ構造が二分木ヒープ (binary heap) である あるオブジェクトO を考える そのオブジェクトは ラベル O. label と値

ガイダンス

JavaプログラミングⅠ

intra-mart Accel Platform — イベントナビゲータ 開発ガイド   初版  

2. データ構造ヒープに保存するデータは 番号付けられて保存される 従って リスト L として保存することとする 3. アルゴリズム 3.1. 要素の追加新しい要素の追加は リストの終端に置くことで開始する つまり 最下層の一番右 または新たに最下層を生成してその一番左となる この後 この要素を正し

第二回独習 Java ゼミ 第二章クラスとメソッド 2.1 メソッドの構造 2.2 静的メソッドと静的変数の概要 2.3 インスタンスメソッドとインスタンス変数の概要 2.4 Integerクラス 2006/04/19 神津健太

Java言語 第1回


やさしいJavaプログラミング -Great Ideas for Java Programming サンプルPDF

プログラミング入門1

PowerPoint プレゼンテーション

デザインパターン入門

Java から見たオブジェクト指向入門 オブジェクト指向 AtoZ セミナー ( 株 ) 豆蔵井上樹

Java プログラミング Ⅰ 3 回目変 数 今日の講義講義で学ぶ内容 変数とは 変数の使い方 キーボード入力の仕方 変 数 変 数 一時的に値を記憶させておく機能 変数は 型 ( データ型 ) と識別子をもちます 2 型 ( データ型 ) 変数に記憶する値の種類変数の型は 記憶できる値の種類と範囲

Transcription:

続 デザインパターン入門 1. はじめに 前回 デザインパターンとは何か? を学びました なんか難しそう とか エラい人 のためのものでしょ? って思う人も多いかもしれませんが 実はそんなことないですよ ー という話もしましたね デザインパターンとは プログラムのお手本集 であり 実は知らず知らずのうちに使っ ているもの オブジェクト指向の話そのもののパターンもある といったお話もしました また コーディングの経験不足を補うもの であることもお話しました それからデザインパターンがいつごろ誕生したか 2000 年です Java の誕生と同じタイミ ングです そのとき 基本の 23 パターンを提唱したのが GoF ( Gang Of Four, 四人組 ) といわれる外国人 4 人だという話もしました 今回は 23 のうちから代表的な 3 つに絞って より詳しく見ていきましょう 2. 詳しく見る 1-Singleton パターン Singleton パターンは並み居るパターンのうちでももっともシンプルかつよく使われるパ ターンです 通常 クラスからインスタンスを作成する際に new をしてインスタンスを得ますが これ だとインスタンスがいくつでも作れます 普通はそれでかまわないんですが 何回作ってもまったく同じインスタンス という場合 もあります であれば 何個も作らずに 1 個だけ作って使いまわした方が効率がいいです ね? この仕組みをカタログ化したのが Singleton パターンです 実装面で言うと まず パターンを適用したいクラスに そのクラスのインスタンスを保持する static なフィールドを設けます さらに そのクラスのインスタンスを得るための static なメソッドを実装します 多くの場合 このメソッドには getinstance() の名前が付きます - 1 -

getinstance() がやる内容は 前述の static フィールドの値を返却する ただそれだけです コーディング例を挙げます public class SomeClass { private static SomeClass someclass = new SomeClass(); public static SomeClass getinstance() { return someclass; こうすると この SomeClass クラスのインスタンスは getinstance() メソッドを呼ぶことで 得ることができます 返ってくるインスタンスは常にこのクラスが static に保持している インスタンスですので 無駄にインスタンスを作らなくて済みますね でも 実はこのままだと この getinstance() を呼ばなくても new でインスタンスが作れち ゃいます みんながみんなこのメソッドを使ってくれるとは限らないですから これだけ だと効果が薄いんですね そこで new できないように コンストラクタを private にしちゃいます public class SomeClass { private SomeClass() { private static SomeClass someclass = new SomeClass(); public static SomeClass getinstance() { return someclass; この状態だと SomeClass を new しようとした途端 Eclipse に コンストラクター SomeClass は不可視です とコンパイルエラーを突きつけられます - 2 -

でもちょっとまって! インスタンスが 1 個しか必要ないなら 単にメソッドを全て static にしてしまって インスタンス化せずに利用できるクラスにすればいいのでは? そう思ったあなた 賢いです でも ちゃんと Singleton パターンを適用するのには理由があるんです (1) static にするとメソッドのオーバーライドができなくなってしまう ( ア ) 拡張されたクラスを作りたくても作れない ( イ ) テストするときにスタブが作りにくい (2) static にするとインスタンスを複数にできない (Singleton はインスタンスが1つとは限らない ) つまり拡張性や保守性を考えれば static で実装するよりも Singleton パターンで実装した 方がよいということです ところで余談ですが 先の例では static フィールド someclass に初期値として SomeClass クラスのインスタンスを設定していましたが 実は null で初期化しておいて getinstance() の中でインスタンス化するほうが一般的です 次のようなコードになります public class SomeClass { private SomeClass() { private static SomeClass someclass = null; public static SomeClass getinstance() { if (someclass == null) { someclass = new SomeClass(); return someclass; getinstance の中で someclass が null かどうか判定し null の場合はインスタンス化を行っています こうするのには理由があります この例ではこのクラスはとてもシンプルですが もっと複雑なクラスだった場合 あるいはインスタンス化の手続きが重い ( 時間のかかる処理がたくさんある ) 場合だと このクラスが参照された瞬間にインスタンス化が実行されてしまうのはよくないからです 利用するときになって初めてインスタンス化が行われたほうが マシンにかかる負荷の点でも 起動時に利用者を待たせるかもしれない可能性を考えても良いということになります - 3 -

問題 (1) 内部に StringBuilder のインスタンスを保持していて文章生成を行うクラス SenetenceGenerator を用意しました またそのクラスを利用して文章を生成する main メソッドを持つクラス Main も用意しました しかし 現状は結果として空文字列が表示されてしまいます Singleton パターンを適用して 正しく文章が表示されるようにしましょう 3. 詳しく見る 2-Iterator パターン Iterator パターンは JDK に Iterator というインタフェースがあるので Java のみな さんおなじみかと思います.NET の方なら Enumerator といえばおわかりいただけ るでしょうか とりあえず例を見て見ましょう 以下のような おもちゃ を表現するための Toy ク ラスがあるとします package toybox.easyversion; public class Toy { private String name; public Toy(String name) { this.name = name; public String getname() { return name; - 4 -

この Toy クラスのインスタンスの集合体である ToyBox クラスがあるとします package toybox.easyversion; public class ToyBox { private Toy[] toys = new Toy[256]; private int last = 0; public Toy get(int index) { return toys[index]; public void add(toy toy) { this.toys[last] = toy; last++; public int getlength() { return last; public ToyBoxIterator iterator() { ToyBoxIterator it = new ToyBoxIterator(this); return it; このおもちゃ箱クラスは 256 個までおもちゃインスタンスを格納できます なお 簡単 のため判定処理が入っていないので 257 個めを入れようとするとエラーになります そしてこのクラスには反復子 ( イテレータ ) のインスタンスを得るためのメソッド iterator() があります 反復子は以下のようなメソッドで構成されます hasnext() メソッド 次のオブジェクトが存在するか否かを boolean 値で返す next() メソッド 次のオブジェクトを取得しつつ インデックスを前に進める - 5 -

package toybox.easyversion; public class ToyBoxIterator { private ToyBox toybox; private int index; public ToyBoxIterator(ToyBox toybox) { this.toybox = toybox; this.index = 0; public boolean hasnext() { boolean result = index < toybox.getlength(); return result; public Toy next() { Toy toy = toybox.get(index); index++; return toy; またフィールドとしておもちゃ箱インスタンスを保持します hasnext() や next() のメ ソッドはこのインスタンスについて次の有無を確認したり取り出して返したりします このクラスを群を利用して複数のおもちゃインスタンスを管理すると 次のようなコー ドになります package toybox.easyversion; public class Main { public static void main(string[] args) { // おもちゃをおもちゃ箱に 4 つ格納 ToyBox toybox = new ToyBox(); toybox.add(new Toy(" ヨーヨー ")); toybox.add(new Toy(" おはじき ")); toybox.add(new Toy(" ぬいぐるみ ")); toybox.add(new Toy(" 剣玉 ")); // おもちゃ箱インスタンスからおもちゃ箱反復子 ( イテレータ ) を得る ToyBoxIterator it = toybox.iterator(); // 次がある間取り出して名前を表示する処理を繰り返す while (it.hasnext()) { Toy toy = it.next(); System.out.println(toy.getName()); - 6 -

こうしておくと この繰り返し処理は ToyBox クラスの実装に依存しなくなる つまり ToyBox クラスをどんなに変更しようが この繰り返し部分の変更が不要となります 問題 Toy インスタンスを配列ではなく List で管理するように ToyBox クラスと ToyBoxIterator クラスの実装を変更し 繰り返し処理に変更が必要ないことを確認しましょう さて 上記に示した例は簡単のため シンプルに書きましたが 実際にはもっと汎用性を高めるため インタフェースを使用して表現するのが普通です まず 集合体となるクラス 上記の例では ToyBox クラスですが が iterator() メソッドを持つようにインタフェースを用意し ToyBox クラスに実装させます package toybox; public interface Aggregate { public abstract Iterator iterator(); package toybox; public class ToyBox implements Aggregate { private Toy[] toys = new Toy[256]; private int last = 0; public Toy get(int index) { return toys[index]; public void add(toy toy) { this.toys[last] = toy; last++; public int getlength() { return last; public Iterator iterator() { Iterator it = new ToyBoxIterator(this); return it; - 7 -

Aggregate とは 集合体 という意味です 何かの集合体であるクラスにはこのインタフェースを実装させる というルールにすれば必然的に Iterator を返すような iterator() メソッドを実装することになります 次に Iterator インタフェースを用意して反復子クラス 例では ToyBoxIterator クラスです に 実装させます Iterator インタフェースはメソッドとして next() と hasnext() を実装することを要求します package toybox; public interface Iterator { public abstract boolean hasnext(); public abstract Object next(); package toybox; public class ToyBoxIterator implements Iterator { private ToyBox toybox; private int index; public ToyBoxIterator(ToyBox toybox) { this.toybox = toybox; this.index = 0; public boolean hasnext() { boolean result = false; if (index < toybox.getlength()) { result = true; return result; public Object next() { Toy toy = toybox.get(index); index++; return toy; このようにすることで 例えばこれが ToyBox クラスではなく全然別な集合体を扱う場合でも 同じように扱うことができます - 8 -

main のクラスは次のようになります package toybox; public class Main { public static void main(string[] args) { // おもちゃをおもちゃ箱に 4 つ格納 ToyBox toybox = new ToyBox(); toybox.add(new Toy(" ヨーヨー ")); toybox.add(new Toy(" おはじき ")); toybox.add(new Toy(" ぬいぐるみ ")); toybox.add(new Toy(" 剣玉 ")); // おもちゃ箱インスタンスから反復子 ( イテレータ ) を得る Iterator it = toybox.iterator(); // 次がある間取り出して名前を表示する処理を繰り返す while (it.hasnext()) { Toy toy = (Toy)it.next(); System.out.println(toy.getName()); ToyBox クラスをインスタンス化して Toy インスタンスを詰め込むところは一緒です next() メソッドが汎用化のために戻り値の方が Object になったことで キャストが必要になってしまいましたがあとは一緒です 宿題 実際にこのクラスを作成しましょう 実は続きがあります 汎用化したものをさらに使いやすくするため JDK5.0 以降に導入されている ジェネリクス宣言 を使うと 集合体に何のクラスのインスタンスが入るのかを指定することができるようになります 普段 Java や.NET でコーディングしていると List<String> だのと書くこともあると思いますが あれです ここでは基本をおさえるということで そこまではやりませんが頭の片隅にいれておいていただけるといいかと思います - 9 -

4. 詳しく見る 3-FlyWeight パターン 3 つめは FlyWeight パターンを見て見ましょう ( 前回とまったく同じでは面白くないので :-p) FlyWeight というのはボクシングでいう フライ級 のことです コーディングにおいてはなにをフライ級にする (= 減量する ) かというと メモリに保持するインスタンスです 例を見て見ましょう /** * インスタンスを 1 つ作るのにとても時間とメモリを食うクラス */ public class HeavyObject { private Object heavydata; public Object getheavydata() { return heavydata; /** * コンストラクタ 引数を元にして フィールドの値を設定する * @param seed */ public HeavyObject(String seed) { this.heavydata = generateheavydata(seed); /** * 何か重い処理をして メモリを食うような重い結果を生成して返すメソッド * @param seed * @return */ private Object generateheavydata(string seed) { // ここで何か重い処理をして メモリを食うような重い結果を生成 try { Thread.sleep(1000); catch (InterruptedException e) { // 重い物を返す ( イメージ ) return seed; 上記は インスタンスを作るのにすごく時間がかかって かつメモリを大量に消費するクラスです 簡単のために 重い重い といいつつシンプルな処理になっていて 時間がかかるといっても sleep しているだけですが ( 笑 ) 実際の現場の開発では本当に時間とメモリを消費するようなクラスは存在します 例えば計算に時間がかって かつ結果データがすごく大きい などです - 10 -

このクラスのインスタンスをいくつか作る処理があるとします public static void main(string[] args) { HeavyObject objt = new HeavyObject("T"); HeavyObject objh = new HeavyObject("H"); HeavyObject obji = new HeavyObject("I"); HeavyObject objs = new HeavyObject("S"); HeavyObject obji2 = new HeavyObject("I"); HeavyObject objs2 = new HeavyObject("S"); HeavyObject obja = new HeavyObject("A"); HeavyObject objp = new HeavyObject("P"); HeavyObject obje = new HeavyObject("E"); HeavyObject objn = new HeavyObject("N"); System.out.println(objI); System.out.println(objI2); アルファベットを 1 文字ずつコンストラクタに渡し 10 個のインスタンスを作っています 1 個のインスタンスを作るのに 1 秒かかるとすると 合計 10 秒かかります また 1 個のインスタンスがメモリを 1 メガバイト消費するとすると 合計 10 メガバイトのメモリが消費されます 最後に変数 obji と obji2 を表示していますが コンストラクタに渡す引数は同じでも当然違うインスタンスなので 違う値が表示されます 出力例 mysample.heavyobject@26db62 mysample.heavyobject@10d0630 しかし obji と obji2 が持っている内部データはどう考えても同じのはずです だから インスタンスを 2 つ作ってしまうのはムダ では次のようなコードだったらどうでしょう? - 11 -

public static void main(string[] args) { HeavyObject objt = HeavyObjectGenerator.getHeavyObject("T"); HeavyObject objh = HeavyObjectGenerator.getHeavyObject("H"); HeavyObject obji = HeavyObjectGenerator.getHeavyObject("I"); HeavyObject objs = HeavyObjectGenerator.getHeavyObject("S"); HeavyObject obji2 = HeavyObjectGenerator.getHeavyObject("I"); HeavyObject objs2 = HeavyObjectGenerator.getHeavyObject("S"); HeavyObject obja = HeavyObjectGenerator.getHeavyObject("A"); HeavyObject objp = HeavyObjectGenerator.getHeavyObject("P"); HeavyObject obje = HeavyObjectGenerator.getHeavyObject("E"); HeavyObject objn = HeavyObjectGenerator.getHeavyObject("N"); System.out.println(objI); System.out.println(objI2); HeavyObjectGenerator というインスタンスを生成するためのクラスが登場しますが それは例えばこんなコードで書かれます package mysample; import java.util.hashmap; import java.util.map; /** * HeavyObject インスタンスを作るクラス */ public class HeavyObjectGenerator { private HeavyObjectGenerator() { private static Map<String, HeavyObject> instancepool = new HashMap<String, HeavyObject>(); public static HeavyObject getheavyobject(string s) { if (!instancepool.containskey(s)) { instancepool.put(s, new HeavyObject(s)); return instancepool.get(s); instancepool というフィールド変数がインスタンスを保持しておくプールになっていて getheavyobject() メソッドにおいてはすでに存在するインスタンスであればそこから引っ張りだされて返却されます もし存在しなければ 新たに new されます main メソッドが実行されると 次のように表示されます 出力例 mysample.heavyobject@921a90 mysample.heavyobject@921a90-12 -

つまり obji と obji2 はまったく同じインスタンスです T I S I T S I H S H 同じものは 1 つずつで十分! 問題 実際にこのクラスを作成しましょう その際 実際に速度の差がわかるように main メソッドは次のように書きましょう public static void main(string[] args) { long start = System.currentTimeMillis(); // ( インスタンス取得 表示処理 ) long end = System.currentTimeMillis(); System.out.println((end - start) / 1000); 5. まとめ 今回は 23 のパターンのうち 3 つにしぼって少し詳しく解説しました たった 3 つですが 少しでもデザインパターンを知ることの価値 意義を感じていただけたら幸いです 次回は 11 月上旬を予定しております 実際の現場の開発ではどういった面に使われているのかを学べたらいいなと考えて鋭意ネタを仕込んでおります 乞うご期待 今日のソースファイル https://docs.google.com/file/d/0b9mqqemgri2wlu96rjloulbysee/edit?usp=sharing - 13 -