11 ソフトウェア工学 Software Engineering デザインパターン DESIGN PATTERNS デザインパターンとは? デザインパターン 過去のソフトウェア設計者が生み出したオブジェクト指向設計に関して, ノウハウを蓄積し 名前をつけ 再利用しやすいようにカタログ化したもの 各デザインパターンの主な内容 そのデザインパターンの目的と効果 どのような役割の部品 ( クラス, インタフェース ) が必要か それらの部品をどのように組み立てるか 個々の部品がどのように関連して大きな機能を果たすのか 1
デザインパターンの例 生成に関するパターン Factory Method Singleton スーパークラスでインスタンスの作り方を抽象的に定め, 具体的な作成はサブクラスにまかせる クラスのインスタンスが一つしかないことを保証する 構造に関するパターン Adapter 異なるインタフェースをもつ2つのクラスを接続するクラスを作る Facade 振る舞いに関するパターン Iterator Template Method Observer 複数のサブシステムの窓口となる共通のインタフェースを提供してシステムをシンプルにする 複数の要素をもつ集合体の要素を 1 つ 1 つ順番にアクセスする方法を提供する 必要な処理の一部をテンプレートとして抽象的に記述し, その具体的内容 ( カスタマイズ ) をサブクラスにまかせる 状態が変化するクラスと, その変化を通知してもらうクラスを分けて設計する 今回の授業では,Template Method パターンと Adapter パターンを具体的に学び, Factory Method パターンの調査を演習課題とする Template Method パターン 必要な処理の一部をテンプレートとして抽象的に記述し, その具体的内容 ( カスタマイズ ) をサブクラスにまかせる. いろいろな人がカスタマイズを考案し, それを簡単に実装できる. 2
テンプレートの概念 抽象カード ( テンプレート ) 処理の枠組み (framework) を定め, 細部はがカスタマイズできる printcard( ){ ( ); 枠組みはテンプレートで実装済み 抽象メソッドは未実装 ( カスタマイズ可能な部分 ) 実装 1 () { 画像をプリント 具体カード 祝誕生! 実装 2 () { 文字列をプリント 1 2 テンプレートのデザイン 抽象カード ( スーパクラス ) AbstractCard printcard printframe テンプレート テンプレートメソッド 抽象メソッド ImageCard image: Image 具体カード ( サブクラス ) StringCard : String 実装 実装 3
AbstractCard クラス Java による記述 抽象クラス public abstract class AbstractCard { public void printcard(graphics g) { printframe(g); (g); AbstractCard printcard printframe テンプレートメソッド public void printframe(graphics g) { 省略 // g を使って枠を表示する高品質のプログラム public abstract void (Graphics g); 抽象メソッド StringCard クラス StringCard : String public class StringCard AbstractCard{ private String ; サブクラスの定義 public StringCard(String str) { = str; コンストラクタ public void (Graphics g) { g.drawstring(, 140, 70); (140, 70) は表示する位置の x-y 座標 4
ImageCard クラス ImageCard image: Image サブクラスの定義 public class ImageCard AbstractCard{ private Image image; public ImageCard(Image img) { image = img; コンストラクタ public void (Graphics g) { g.drawimage(image, 140, 70); ( 実際にはもう少し複雑な実装となる ) AbstractCard 利用のしかた printcard(g) printframe(g) (g) ImageCard image: Image (g) StringCard : String (g) public void printtwocards(graphics g, Image img, String str) { AbstractCard cardholder[2]; cardholder[0] = new ImageCard(img); cardholder[1] = new StringCard(str); for(int i=0; i<2; i++) { cardholder[i].printcard(g); AbstractCard が規定する統一的なインタフェース 5
ホットスポット AbstractCard printcard abstract superclass 高度なサービス内容が書かれているが, このままでは動かない concrete subclass ニーズに合わせて簡単にカスタマイズ済みであり, このままで動く template method ( サービス ) printframe abstract method concrete method hot spot implementation ( カスタマイズ ) Template Method パターン 一般化すると, つぎのデザインパターンが得られる Template Method パターン AbstractClass - 抽象メソッド primitiveoperations を定義し - それを使い, アルゴリズムの枠組みを定義する templatemethod を実装 ConcreteClass - この具体クラス特有の処理を実行するように primitiveoperations を実装 AbstractClass templatemethod primitiveoperation1 primitiveoperation2 ConcreteClass primitiveoperation1 primitiveoperation2 6
Template Method パターンのありがたみ システムプラグラマの立場からのありがたみ のインタフェースだけをアプリプログラマに示せばよく, printcard と printframe のソースコードを公開しなくてよい すべてのアプリに影響を与えずに,printCard と printframe の実装の修正が可能 システムプラグラマが作成 AbstractCard printcard(g) printframe(g) (g) アプリケーションプラグラマの立場からのありがたみ printcard と printframe のコードを修正することなく, のみを実装すればよい ImageCard も StringCard も AbstractCard の一種なので, その統一的なインタフェース (API) である printcard を利用してアプリを作成可能 ImageCard image: Image (g) StringCard : String (g) 異なるアプリプラグラマが作成 Adapter パターン 異なるインタフェースをもつ 2 つのクラスを接続する. 開発するシステムのインタフェースを変えずに, 外部のいろいろなインタフェースに接続できる. 7
アダプターの概念 例 クラス 抽象メソッド アダプター クラス print 2 つの異なるインタフェース ( クラス ) が固定されていて変更できないとき, 両者を接続するクラス 提供されているもの クラスがプリンタメーカーから提供済. usb.print( ) により を印字可. 欲しいもの クラスの 抽象メソッドを実装したクラス ( アダプター ). ( それにより,gamePrinter.( ) によって を印字できるようになる.) 委譲を使うデザイン (1/4) (delegation) アダプタークラス クラス Adapter?? クラス print public abstract class { public abstract void ( ); に対して が隠されている public static void main(string[ ] args) { gp = new Adapter( You win! ); gp.( ); Adapter は, でもある public class { private String ; public (String str) {.. public void print() {.. 実際にはクラスファイルのみ提供 8
委譲を使うデザイン (2/4) スーパークラス print 継承 サブクラス Adapter usb: Adapter は,でもある has a 委 usb.print( ) 譲 (delegation) 委譲を使うデザイン (3/4) Adapter usb: has a print public class Adapter { private usb; public Adapter(String str) { usb = new (str); public void () { usb.print(); コンストラクタ 委 譲 9
委譲を使うデザイン (4/4) 一般化すると, つぎのデザインパターンが得られる Adaper パターン Client: Target オブジェクトを利用する Target: Client が使用できる特定のインタフェースを規定する Adaptee: 適合させたい既存のインタフェースをもつ実装 Adapter: Adaptee のインタフェースを Target のインタフェースに適合させる 依頼者 Client 対象アダプター適合される側 Target Adapter Adaptee has a adaptee request request specificrequest 委 譲 adaptee.specificrequest() Adapter パターンのありがたみ (1/2) アプリケーションプラグラマの立場からのありがたみ と のソースコードを修正することなく, から見たインタフェース () を変えずに Adapter を作成可能 以外との様々な Adapter を実装したとき, どれも の一種なので, は統一的なインタフェース (API) を利用してアプリを作成可能 Adapter usb: has a print 異なるアプリプラグラマが作成 異なるシステムプラグラマが作成 10
Adapter パターンのありがたみ (2/2) システムプラグラマの立場からのありがたみ と に影響を与えずに (print) の実装を変更可能 アプリプログラマに と のソースコードを公開しなくてもよい Adapter usb: has a print 異なるアプリプラグラマが作成 異なるシステムプラグラマが作成 演習問題 11 Factory Method パターンについて調べ, 概略を説明し, パターンの構造を図示しなさい. 11