SlideShare una empresa de Scribd logo
1 de 42
GoFデザインパターン 2009
インフラ勉強会 2021-10-09 @miwarin
お題
● fukabori.fm で t_wada さんが言ってた
● 削除されたパターン・追加されたパターン
fukabori.fm で t_wada さんが言ってた
https://fukabori.fm/episode/49
「テスト駆動開発」著者Kent Beck 著/和田 卓人 訳
https://shop.ohmsha.co.jp/shopdetail/000000004967/
fukabori.fm で t_wada さんが言ってた
t_wada さんて?
fukabori.fm で t_wada さんが言ってた
「テスト書いてないとかお前それ〜」が私の代名詞になるまで。テスト駆動開発とともに歩んだキャリア
https://engineer-lab.findy-code.io/t-wada
fukabori.fm で t_wada さんが言ってた
● fukabofi.fm 49 の話題
○ オブジェクト指向プログラミングについての誤解が広まった
○ デザインパターンの狙い
○ デザインパターンと自動テストとリファクタリング
○ デザインパターンが更新された
fukabori.fm で t_wada さんが言ってた
● オブジェクト指向プログラミングについての誤解が広まった
○ 誤解「オブジェクト指向プログラミング = 継承を使いこなすこと」
○ 継承が深すぎると誰を変更すると何に影響があるのか把握できない。依存が深すぎて何が起
きるか分からない。もはやスパゲティコード
fukabori.fm で t_wada さんが言ってた
継承が深い図
fukabori.fm で t_wada さんが言ってた
● デザインパターンの狙い
○ 継承ではなく、委譲やコンポジションを使って実装する
■ 委譲: デリゲート
■ コンポジション: オブジェクトの組み合わせ
○ デザインパターンを再利用するのではなく、デザインパターンを利用する側を再利用する
■ 実装に対してではなく、インターフェースに対してプログラミングする
■ 実装がどうであれ、このように振る舞ってほしい
fukabori.fm で t_wada さんが言ってた
利用する側を再利用する
デザインパターン
クライアント
クライアント
デザインパターンを再利
用するのでなく
デザインパターン
fukabori.fm で t_wada さんが言ってた
● デザインパターンと自動テストとリファクタリング
○ プログラミング言語などの年代
■ 1983 C++ : C with ClassesからC++に名称を変更した
■ 1985 「The C++ Programming Language」
■ 1994 python 1.0
■ 1994 「Design Patterns」
■ 1996 Java (JDK 1.0)
■ 1996 ruby 1.0
■ 1999 「Refactoring」(リファクタリング)
■ 2000「Extreme Programming Explained(XPエクストリーム・プログラミング入門)
■ 2002「Test-Driven Development (テスト駆動開発入門)」
■ 2008 Hudson 1.200
■ 2011 Jenkins 1.396
fukabori.fm で t_wada さんが言ってた
● 自動テストとリファクタリングの影響
● あとから設計変更すればよさげ
● 実際にコードを書いてみて変更に強い設計を作っていく
● ここは変わるだろうと備えてデザインパターンで設計しておいたけど実際に
はそこは変化しなかった
● 現状との差異が生じたらリファクタリングする
fukabori.fm で t_wada さんが言ってた
● リファクタリングしてデザインパターンへ近づけていく
● リファクタリングのゴールがデザインパターン
fukabori.fm で t_wada さんが言ってた
Design Patterns 15 Years Later: An Interview with Erich Gamma, Richard Helm, and Ralph Johnson
https://www.informit.com/articles/article.aspx?p=1404056
● 2009年のGoF(Gang of Four) へのイン
タビュー
○ Erich Gamma
○ Richard Helm
○ Ralph Johnson
○ John Vlissides (故人)
● リファクタリングによってデザインパ
ターンに近づけていく
● プログラミング言語自体にデザインパ
ターンが実装されている場合もあるな
ら不要だよね
fukabori.fm で t_wada さんが言ってた
● 旧
○ 生成
○ 構造
○ 振る舞い
● 新
○ コア(よく使われるパターン。これだけでも覚えておくとリファクタリングが捗る)
○ 生成
○ ペリフェラル(コアではない)
○ そのほか
カテゴリが変更された
fukabori.fm で t_wada さんが言ってた
カテゴリが変更された
fukabori.fm で t_wada さんが言ってた
● 削除されたパターン
○ Singleton
○ Adapter
○ Bridge
○ Chain of responsibility
○ Memento
○ Observer
● 追加されたパターン
○ Dependency Injection
○ Type Object
○ Null Object
○ Extension Object
パターンも変更された
削除されたパターン
● Singleton
● Adapter
● Bridge
● Chain of responsibility
● Memento
● Observer
削除されたパターン
Singletonパターン
インスタンスを 1 つしか作ってはいけない
● メリット: 資源(データベースやファイルシステム)を管理するインスタンスをただ 1 つ提供する
● デメリット: ようするにグローバル変数なので、すべてのコードがこのシングルトンの実装を知って
いなければならない。結合度が高くなる
削除されたパターン
public class Singleton
{
private static Singleton theInstance = null;
private Singleton() { }
public static Singleton Instance()
{
if (theInstance == null)
theInstance = new Singleton();
return theInstance;
}
}
Singletonパターン
「アジャイルソフトウェア開発の奥義」p. 231
削除されたパターン
Adapterパターン
既存のクラスをラッピングしてインターフェースを追加する
削除されたパターン
interface ProductPrice{
public int getPrice();
}
class Product{
private int cost;
public int getCost(){
return cost;
}
}
class ProductAdapter implements ProductPrice{
private Product product = new Product();
public int getPrice(){
return product.getCost();
}
}
Adapterパターン
Adapter パターン
https://ja.wikipedia.org/wiki/Adapter_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
interface ProductPrice{
public int getPrice();
}
class Product{
private int cost;
public int getCost(){
return cost;
}
}
class ProductAdapter extends Product implements
ProductPrice{
public int getPrice(){
return this.getCost();
}
}
継承を使って実装 委譲を使って実装
削除されたパターン
Bridgeパターン
抽象化と実装を分離する(?)
削除されたパターン
class DrawingAPI:
__metaclass__ = ABCMeta
@abstractmethod
def draw_circle(self, x, y, radius):
raise NotImplementedError(NOT_IMPLEMENTED)
class DrawingAPI1(DrawingAPI):
def draw_circle(self, x, y, radius):
return f"API1.circle at {x}:{y} - radius: {radius}"
class DrawingAPI2(DrawingAPI):
def draw_circle(self, x, y, radius):
return f"API2.circle at {x}:{y} - radius: {radius}"
class DrawingAPI3(DrawingAPI):
def draw_circle(self, x, y, radius):
return f"API3.circle at {x}:{y} - radius: {radius}"
class Shape:
__metaclass__ = ABCMeta
drawing_api = None
def __init__(self, drawing_api):
self.drawing_api = drawing_api
@abstractmethod
def draw(self):
raise NotImplementedError(NOT_IMPLEMENTED)
@abstractmethod
def resize_by_percentage(self, percent):
raise NotImplementedError(NOT_IMPLEMENTED)
Bridgeパターン
Bridge pattern
https://en.wikipedia.org/wiki/Bridge_pattern
class CircleShape(Shape):
def __init__(self, x, y, radius, drawing_api):
self.x = x
self.y = y
self.radius = radius
super(CircleShape, self).__init__(drawing_api)
def draw(self):
return self.drawing_api.draw_circle(self.x, self.y, self.radius)
def resize_by_percentage(self, percent):
self.radius *= 1 + percent / 100
class BridgePattern:
@staticmethod
def test():
shapes = [
CircleShape(1.0, 2.0, 3.0, DrawingAPI1()),
CircleShape(5.0, 7.0, 11.0, DrawingAPI2()),
CircleShape(5.0, 4.0, 12.0, DrawingAPI3()),
]
for shape in shapes:
shape.resize_by_percentage(2.5)
print(shape.draw())
BridgePattern.test()
削除されたパターン
Bridgeパターン
削除されたパターン
Chain of responsibilityパターン
処理をするオブジェクトと、処理の順番を制御するオブジェクトを分離する
削除されたパターン
import java.util.*;
abstract class Logger {
public static final int ERROR = 3;
public static final int NOTICE = 5;
public static final int DEBUG = 7;
private final int mask;
protected Logger(int mask) { this.mask = mask; }
// The next element in the chain of responsibility
protected Logger next;
public Logger setNext(Logger l) {
next = l;
return this;
}
public void message(String msg, int priority) {
if (priority <= mask) {
writeMessage(msg);
if (next != null) {
next.message(msg, priority);
}
}
}
abstract protected void writeMessage(String msg);
}
Chain of responsibilityパターン
Chain of Responsibility パターン
https://ja.wikipedia.org/wiki/Chain_of_Responsibility_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
class StdoutLogger extends Logger {
public StdoutLogger(int mask) { super(mask); }
@Override
protected void writeMessage(String msg) {
System.out.println("Writting to stdout: " + msg);
}
}
class EmailLogger extends Logger {
public EmailLogger(int mask) { super(mask); }
@Override
protected void writeMessage(String msg) {
System.out.println("Sending via email: " + msg);
}
}
class StderrLogger extends Logger {
public StderrLogger(int mask) { super(mask); }
@Override
protected void writeMessage(String msg) {
System.out.println("Sending to stderr: " + msg);
}
}
削除されたパターン
Chain of responsibilityパターン
public class ChainOfResponsibilityExample {
public static void main(String[] args) {
// Build the chain of responsibility
final Logger l =
new StdoutLogger(Logger.DEBUG).setNext(
new EmailLogger(Logger.NOTICE).setNext(
new StderrLogger(Logger.ERROR)));
// Handled by StdoutLogger
l.message("Entering function y.", Logger.DEBUG);
// Handled by StdoutLogger and EmailLogger
l.message("Step1 completed.", Logger.NOTICE);
// Handled by all three loggers
l.message("An error has occurred.", Logger.ERROR);
}
}
削除されたパターン
Chain of responsibilityパターン
削除されたパターン
Mementoパターン
オブジェクトを以前の状態に(ロールバックにより)戻す
削除されたパターン
class Originator
class Memento
def initialize(state)
@state = state.dup
end
def state
@state.dup
end
end
attr_accessor :state
def save_to_memento
Memento.new(@state)
end
def restore_from_memento(m)
@state = m.state
end
end
describe Originator do
before(:all) do
@caretaker = Caretaker.new
@originator = Originator.new
@originator.state = "State1"
end
it "should have original state" do
@originator.state.should == 'State1'
end
it "should update state" do
@originator.state = "State2"
@originator.state.should == 'State2'
end
it "should save memento" do
@caretaker << @originator.save_to_memento
@caretaker.size.should == 1
end
以下略
Mementoパターン
Memento パターン
https://ja.wikipedia.org/wiki/Memento_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
削除されたパターン
Observerパターン
1 対 多 の関係
オブジェクトの変化があったとき、依存するすべてのオブジェクトへ通知される
● サブジェクト: 通知するひと
● オブザーバー: 通知を受け取るひと
実装としては、サブジェクトに登録しておいたメソッドを順に呼び出すだけ。同期処理です。
非同期処理の場合は「イベント」や「メッセージ」などと呼んで区別することもあるらしい。
削除されたパターン
Observerパターン
Observer pattern
https://en.wikipedia.org/wiki/Observer_pattern
class Observable:
def __init__(self):
self._observers = []
def register_observer(self, observer):
self._observers.append(observer)
def notify_observers(self, *args, **kwargs):
for obs in self._observers:
obs.notify(self, *args, **kwargs)
class Observer:
def __init__(self, observable):
observable.register_observer(self)
def notify(self, observable, *args, **kwargs):
print("Got", args, kwargs, "From", observable)
subject = Observable()
observer = Observer(subject)
subject.notify_observers("test", kw="python")
追加されたパターン
● Dependency Injection
● Type Object
● Null Object
● Extension Object
追加されたパターン
Dependency Injectionパターン
あるオブジェクト(サービス)を別のオブジェクト(クライアント)に渡す
class Client
{
private $service;
public function __construct(Service $service)
{
$this->service = $service;
}
public function doSomething()
{
$this->service->doSomething();
}
}
class Service
{
public function doSomething()
{
}
}
class Client
{
private $service;
public function __construct()
{
$this->service = new Service();
}
public function doSomething()
{
$this->service->doSomething();
}
}
class Service
{
public function doSomething()
{
}
}
追加されたパターン
Dependency Injectionパターン
やはりあなた方のDependency Injectionはまちがっている。
http://blog.a-way-out.net/blog/2015/08/31/your-dependency-injection-is-wrong-as-I-expected/
DIパターン
DIパターンでない
追加されたパターン
Type Objectパターン
型を動的に作成する
どのような型が必要になるのか、前もって分からない場合に使う
追加されたパターン
Type Objectパターン
class TypeObject
def initialize(name, value)
@name = name
@value = value
end
def get(name)
return @value
end
end
def main(argv)
t1 = TypeObject.new("a", "AAAA")
t2 = TypeObject.new("b", "BBBB")
puts(t1.get("a"))
puts(t2.get("b"))
end
main(ARGV)
追加されたパターン
Null Objectパターン
何もしないオブジェクト
0 と 1 を同一視する
Null だったらこうする、という条件分岐をオブジェクトへ分離する
追加されたパターン
Null Objectパターン
Employee e = DB.getEmployee("Bob");
if(e != null && e.isTimeToPay(today))
e.pay()
Employee e = DB.getEmployee("Bob");
if(e.isTimeToPay(today))
e.pay()
「アジャイルソフトウェア開発の奥義」pp. 243-246
Null Objectパターンでない Null Objectパターン
追加されたパターン
Extension Objectパターン
既存のクラス階層構造に影響を与えずに機能を追加する
追加されたパターン
Extension Objectパターン
class BOM
def initialize
@ext ||= {}
end
def add(name, ext)
@ext[name] = ext
end
def get(name)
return @ext[name]
end
end
def toXML
return "XML"
end
def toCSV
return "CSV"
end
def main(argv)
bom = BOM.new
bom.add("XML", toXML)
bom.add("CSV", toCSV)
puts(bom.get("XML"))
puts(bom.get("CSV"))
end
main(ARGV)
例:
部品一覧を扱うクラスがある。このクラスに XML や
CSV へ出力する機能を追加したい。
toXML や toCSV というメソッドを追加する手もあるが、
単一責任の原則(SRP)に反する。

Más contenido relacionado

La actualidad más candente

RPGにおけるイベント駆動型の設計と実装
RPGにおけるイベント駆動型の設計と実装RPGにおけるイベント駆動型の設計と実装
RPGにおけるイベント駆動型の設計と実装Koji Morikawa
 
オブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメオブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメYoji Kanno
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean ArchitectureAtsushi Nakamura
 
イベント・ソーシングを知る
イベント・ソーシングを知るイベント・ソーシングを知る
イベント・ソーシングを知るShuhei Fujita
 
Redmine 4.1 新機能評価ガイド <速報版>
Redmine 4.1 新機能評価ガイド <速報版>Redmine 4.1 新機能評価ガイド <速報版>
Redmine 4.1 新機能評価ガイド <速報版>Go Maeda
 
どこに何を書くのか?
どこに何を書くのか?どこに何を書くのか?
どこに何を書くのか?pospome
 
Hatena::Letの式年遷宮
Hatena::Letの式年遷宮Hatena::Letの式年遷宮
Hatena::Letの式年遷宮Takafumi ONAKA
 
リーンなコードを書こう:実践的なオブジェクト指向設計
リーンなコードを書こう:実践的なオブジェクト指向設計リーンなコードを書こう:実践的なオブジェクト指向設計
リーンなコードを書こう:実践的なオブジェクト指向設計増田 亨
 
Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Scott Wlaschin
 
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来についてshinjiigarashi
 
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門
関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門Tadahiro Ishisaka
 
ドメイン駆動設計とマイクロサービス
ドメイン駆動設計とマイクロサービスドメイン駆動設計とマイクロサービス
ドメイン駆動設計とマイクロサービスkouki_mitsuishi
 
serviceクラスをやめようサブクラスを使おう
serviceクラスをやめようサブクラスを使おうserviceクラスをやめようサブクラスを使おう
serviceクラスをやめようサブクラスを使おうよしだ あつし
 
C#でわかる こわくないMonad
C#でわかる こわくないMonadC#でわかる こわくないMonad
C#でわかる こわくないMonadKouji Matsui
 
ドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったことドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったこと増田 亨
 
AI時代の要件定義
AI時代の要件定義AI時代の要件定義
AI時代の要件定義Zenji Kanzaki
 
ソフトウェア開発のやり方の改善
ソフトウェア開発のやり方の改善ソフトウェア開発のやり方の改善
ソフトウェア開発のやり方の改善増田 亨
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介torisoup
 
ドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かすドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かす増田 亨
 
実践的な設計って、なんだろう?
実践的な設計って、なんだろう?実践的な設計って、なんだろう?
実践的な設計って、なんだろう?増田 亨
 

La actualidad más candente (20)

RPGにおけるイベント駆動型の設計と実装
RPGにおけるイベント駆動型の設計と実装RPGにおけるイベント駆動型の設計と実装
RPGにおけるイベント駆動型の設計と実装
 
オブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメオブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメ
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
イベント・ソーシングを知る
イベント・ソーシングを知るイベント・ソーシングを知る
イベント・ソーシングを知る
 
Redmine 4.1 新機能評価ガイド <速報版>
Redmine 4.1 新機能評価ガイド <速報版>Redmine 4.1 新機能評価ガイド <速報版>
Redmine 4.1 新機能評価ガイド <速報版>
 
どこに何を書くのか?
どこに何を書くのか?どこに何を書くのか?
どこに何を書くのか?
 
Hatena::Letの式年遷宮
Hatena::Letの式年遷宮Hatena::Letの式年遷宮
Hatena::Letの式年遷宮
 
リーンなコードを書こう:実践的なオブジェクト指向設計
リーンなコードを書こう:実践的なオブジェクト指向設計リーンなコードを書こう:実践的なオブジェクト指向設計
リーンなコードを書こう:実践的なオブジェクト指向設計
 
Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)
 
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
 
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門
関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門
 
ドメイン駆動設計とマイクロサービス
ドメイン駆動設計とマイクロサービスドメイン駆動設計とマイクロサービス
ドメイン駆動設計とマイクロサービス
 
serviceクラスをやめようサブクラスを使おう
serviceクラスをやめようサブクラスを使おうserviceクラスをやめようサブクラスを使おう
serviceクラスをやめようサブクラスを使おう
 
C#でわかる こわくないMonad
C#でわかる こわくないMonadC#でわかる こわくないMonad
C#でわかる こわくないMonad
 
ドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったことドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったこと
 
AI時代の要件定義
AI時代の要件定義AI時代の要件定義
AI時代の要件定義
 
ソフトウェア開発のやり方の改善
ソフトウェア開発のやり方の改善ソフトウェア開発のやり方の改善
ソフトウェア開発のやり方の改善
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介
 
ドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かすドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かす
 
実践的な設計って、なんだろう?
実践的な設計って、なんだろう?実践的な設計って、なんだろう?
実践的な設計って、なんだろう?
 

Similar a GoF デザインパターン 2009

第2回デザインパターン資料
第2回デザインパターン資料第2回デザインパターン資料
第2回デザインパターン資料gaaupp
 
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~Fujio Kojima
 
Android cleanarchitecture
Android cleanarchitectureAndroid cleanarchitecture
Android cleanarchitectureTomoaki Imai
 
C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~Fujio Kojima
 
復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0Yuta Matsumura
 
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPAkira Takahashi
 
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化するEWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化するKiyoshi Sawada
 
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化するEWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化するKiyoshi Sawada
 
20171212 titech lecture_ishizaki_public
20171212 titech lecture_ishizaki_public20171212 titech lecture_ishizaki_public
20171212 titech lecture_ishizaki_publicKazuaki Ishizaki
 
Wakanda#1
Wakanda#1Wakanda#1
Wakanda#1kmiyako
 
エンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJSエンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJSAyumi Goto
 
Azure IoT Edge で Custom Vision
Azure IoT Edge で Custom VisionAzure IoT Edge で Custom Vision
Azure IoT Edge で Custom VisionYoshitaka Seo
 
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~decode2016
 
TypeScript と Visual Studio Code
TypeScript と Visual Studio CodeTypeScript と Visual Studio Code
TypeScript と Visual Studio CodeAkira Inoue
 
Roslyn による Visual Studio のアドイン
Roslyn による Visual Studio のアドインRoslyn による Visual Studio のアドイン
Roslyn による Visual Studio のアドインFujio Kojima
 
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...Yoshifumi Kawai
 
Implementation patterns
Implementation patternsImplementation patterns
Implementation patternsTatsuya Maki
 
Angular ユーザーなら押さえておきたい! TypeScript と Visual Studio Code の基礎と活用
Angular ユーザーなら押さえておきたい! TypeScript と Visual Studio Code の基礎と活用Angular ユーザーなら押さえておきたい! TypeScript と Visual Studio Code の基礎と活用
Angular ユーザーなら押さえておきたい! TypeScript と Visual Studio Code の基礎と活用Akira Inoue
 

Similar a GoF デザインパターン 2009 (20)

第2回デザインパターン資料
第2回デザインパターン資料第2回デザインパターン資料
第2回デザインパターン資料
 
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
 
Android cleanarchitecture
Android cleanarchitectureAndroid cleanarchitecture
Android cleanarchitecture
 
C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~
 
復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0
 
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JP
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化するEWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
 
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化するEWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
 
20171212 titech lecture_ishizaki_public
20171212 titech lecture_ishizaki_public20171212 titech lecture_ishizaki_public
20171212 titech lecture_ishizaki_public
 
Wakanda#1
Wakanda#1Wakanda#1
Wakanda#1
 
エンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJSエンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJS
 
Azure IoT Edge で Custom Vision
Azure IoT Edge で Custom VisionAzure IoT Edge で Custom Vision
Azure IoT Edge で Custom Vision
 
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
 
TypeScript と Visual Studio Code
TypeScript と Visual Studio CodeTypeScript と Visual Studio Code
TypeScript と Visual Studio Code
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
 
Roslyn による Visual Studio のアドイン
Roslyn による Visual Studio のアドインRoslyn による Visual Studio のアドイン
Roslyn による Visual Studio のアドイン
 
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
 
Implementation patterns
Implementation patternsImplementation patterns
Implementation patterns
 
Angular ユーザーなら押さえておきたい! TypeScript と Visual Studio Code の基礎と活用
Angular ユーザーなら押さえておきたい! TypeScript と Visual Studio Code の基礎と活用Angular ユーザーなら押さえておきたい! TypeScript と Visual Studio Code の基礎と活用
Angular ユーザーなら押さえておきたい! TypeScript と Visual Studio Code の基礎と活用
 

Más de miwarin

RTOS入門 割り込み制御
RTOS入門 割り込み制御RTOS入門 割り込み制御
RTOS入門 割り込み制御miwarin
 
RTOS入門 タスク間同期通信
RTOS入門 タスク間同期通信RTOS入門 タスク間同期通信
RTOS入門 タスク間同期通信miwarin
 
RTOS入門 タスク概要
RTOS入門 タスク概要RTOS入門 タスク概要
RTOS入門 タスク概要miwarin
 
リーンスタートアップとは
リーンスタートアップとはリーンスタートアップとは
リーンスタートアップとはmiwarin
 
マーケティングとは
マーケティングとはマーケティングとは
マーケティングとはmiwarin
 
スクラムとは
スクラムとはスクラムとは
スクラムとはmiwarin
 
Clangとは
ClangとはClangとは
Clangとはmiwarin
 
NetBSDとは
NetBSDとはNetBSDとは
NetBSDとはmiwarin
 
リーンキャンバステンプレ
リーンキャンバステンプレリーンキャンバステンプレ
リーンキャンバステンプレmiwarin
 

Más de miwarin (9)

RTOS入門 割り込み制御
RTOS入門 割り込み制御RTOS入門 割り込み制御
RTOS入門 割り込み制御
 
RTOS入門 タスク間同期通信
RTOS入門 タスク間同期通信RTOS入門 タスク間同期通信
RTOS入門 タスク間同期通信
 
RTOS入門 タスク概要
RTOS入門 タスク概要RTOS入門 タスク概要
RTOS入門 タスク概要
 
リーンスタートアップとは
リーンスタートアップとはリーンスタートアップとは
リーンスタートアップとは
 
マーケティングとは
マーケティングとはマーケティングとは
マーケティングとは
 
スクラムとは
スクラムとはスクラムとは
スクラムとは
 
Clangとは
ClangとはClangとは
Clangとは
 
NetBSDとは
NetBSDとはNetBSDとは
NetBSDとは
 
リーンキャンバステンプレ
リーンキャンバステンプレリーンキャンバステンプレ
リーンキャンバステンプレ
 

GoF デザインパターン 2009

  • 2. お題 ● fukabori.fm で t_wada さんが言ってた ● 削除されたパターン・追加されたパターン
  • 3. fukabori.fm で t_wada さんが言ってた https://fukabori.fm/episode/49
  • 4. 「テスト駆動開発」著者Kent Beck 著/和田 卓人 訳 https://shop.ohmsha.co.jp/shopdetail/000000004967/ fukabori.fm で t_wada さんが言ってた t_wada さんて?
  • 5. fukabori.fm で t_wada さんが言ってた 「テスト書いてないとかお前それ〜」が私の代名詞になるまで。テスト駆動開発とともに歩んだキャリア https://engineer-lab.findy-code.io/t-wada
  • 6. fukabori.fm で t_wada さんが言ってた ● fukabofi.fm 49 の話題 ○ オブジェクト指向プログラミングについての誤解が広まった ○ デザインパターンの狙い ○ デザインパターンと自動テストとリファクタリング ○ デザインパターンが更新された
  • 7. fukabori.fm で t_wada さんが言ってた ● オブジェクト指向プログラミングについての誤解が広まった ○ 誤解「オブジェクト指向プログラミング = 継承を使いこなすこと」 ○ 継承が深すぎると誰を変更すると何に影響があるのか把握できない。依存が深すぎて何が起 きるか分からない。もはやスパゲティコード
  • 8. fukabori.fm で t_wada さんが言ってた 継承が深い図
  • 9. fukabori.fm で t_wada さんが言ってた ● デザインパターンの狙い ○ 継承ではなく、委譲やコンポジションを使って実装する ■ 委譲: デリゲート ■ コンポジション: オブジェクトの組み合わせ ○ デザインパターンを再利用するのではなく、デザインパターンを利用する側を再利用する ■ 実装に対してではなく、インターフェースに対してプログラミングする ■ 実装がどうであれ、このように振る舞ってほしい
  • 10. fukabori.fm で t_wada さんが言ってた 利用する側を再利用する デザインパターン クライアント クライアント デザインパターンを再利 用するのでなく デザインパターン
  • 11. fukabori.fm で t_wada さんが言ってた ● デザインパターンと自動テストとリファクタリング ○ プログラミング言語などの年代 ■ 1983 C++ : C with ClassesからC++に名称を変更した ■ 1985 「The C++ Programming Language」 ■ 1994 python 1.0 ■ 1994 「Design Patterns」 ■ 1996 Java (JDK 1.0) ■ 1996 ruby 1.0 ■ 1999 「Refactoring」(リファクタリング) ■ 2000「Extreme Programming Explained(XPエクストリーム・プログラミング入門) ■ 2002「Test-Driven Development (テスト駆動開発入門)」 ■ 2008 Hudson 1.200 ■ 2011 Jenkins 1.396
  • 12. fukabori.fm で t_wada さんが言ってた ● 自動テストとリファクタリングの影響 ● あとから設計変更すればよさげ ● 実際にコードを書いてみて変更に強い設計を作っていく ● ここは変わるだろうと備えてデザインパターンで設計しておいたけど実際に はそこは変化しなかった ● 現状との差異が生じたらリファクタリングする
  • 13. fukabori.fm で t_wada さんが言ってた ● リファクタリングしてデザインパターンへ近づけていく ● リファクタリングのゴールがデザインパターン
  • 14. fukabori.fm で t_wada さんが言ってた Design Patterns 15 Years Later: An Interview with Erich Gamma, Richard Helm, and Ralph Johnson https://www.informit.com/articles/article.aspx?p=1404056 ● 2009年のGoF(Gang of Four) へのイン タビュー ○ Erich Gamma ○ Richard Helm ○ Ralph Johnson ○ John Vlissides (故人) ● リファクタリングによってデザインパ ターンに近づけていく ● プログラミング言語自体にデザインパ ターンが実装されている場合もあるな ら不要だよね
  • 15. fukabori.fm で t_wada さんが言ってた ● 旧 ○ 生成 ○ 構造 ○ 振る舞い ● 新 ○ コア(よく使われるパターン。これだけでも覚えておくとリファクタリングが捗る) ○ 生成 ○ ペリフェラル(コアではない) ○ そのほか カテゴリが変更された
  • 16. fukabori.fm で t_wada さんが言ってた カテゴリが変更された
  • 17. fukabori.fm で t_wada さんが言ってた ● 削除されたパターン ○ Singleton ○ Adapter ○ Bridge ○ Chain of responsibility ○ Memento ○ Observer ● 追加されたパターン ○ Dependency Injection ○ Type Object ○ Null Object ○ Extension Object パターンも変更された
  • 18. 削除されたパターン ● Singleton ● Adapter ● Bridge ● Chain of responsibility ● Memento ● Observer
  • 19. 削除されたパターン Singletonパターン インスタンスを 1 つしか作ってはいけない ● メリット: 資源(データベースやファイルシステム)を管理するインスタンスをただ 1 つ提供する ● デメリット: ようするにグローバル変数なので、すべてのコードがこのシングルトンの実装を知って いなければならない。結合度が高くなる
  • 20. 削除されたパターン public class Singleton { private static Singleton theInstance = null; private Singleton() { } public static Singleton Instance() { if (theInstance == null) theInstance = new Singleton(); return theInstance; } } Singletonパターン 「アジャイルソフトウェア開発の奥義」p. 231
  • 22. 削除されたパターン interface ProductPrice{ public int getPrice(); } class Product{ private int cost; public int getCost(){ return cost; } } class ProductAdapter implements ProductPrice{ private Product product = new Product(); public int getPrice(){ return product.getCost(); } } Adapterパターン Adapter パターン https://ja.wikipedia.org/wiki/Adapter_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3 interface ProductPrice{ public int getPrice(); } class Product{ private int cost; public int getCost(){ return cost; } } class ProductAdapter extends Product implements ProductPrice{ public int getPrice(){ return this.getCost(); } } 継承を使って実装 委譲を使って実装
  • 24. 削除されたパターン class DrawingAPI: __metaclass__ = ABCMeta @abstractmethod def draw_circle(self, x, y, radius): raise NotImplementedError(NOT_IMPLEMENTED) class DrawingAPI1(DrawingAPI): def draw_circle(self, x, y, radius): return f"API1.circle at {x}:{y} - radius: {radius}" class DrawingAPI2(DrawingAPI): def draw_circle(self, x, y, radius): return f"API2.circle at {x}:{y} - radius: {radius}" class DrawingAPI3(DrawingAPI): def draw_circle(self, x, y, radius): return f"API3.circle at {x}:{y} - radius: {radius}" class Shape: __metaclass__ = ABCMeta drawing_api = None def __init__(self, drawing_api): self.drawing_api = drawing_api @abstractmethod def draw(self): raise NotImplementedError(NOT_IMPLEMENTED) @abstractmethod def resize_by_percentage(self, percent): raise NotImplementedError(NOT_IMPLEMENTED) Bridgeパターン Bridge pattern https://en.wikipedia.org/wiki/Bridge_pattern
  • 25. class CircleShape(Shape): def __init__(self, x, y, radius, drawing_api): self.x = x self.y = y self.radius = radius super(CircleShape, self).__init__(drawing_api) def draw(self): return self.drawing_api.draw_circle(self.x, self.y, self.radius) def resize_by_percentage(self, percent): self.radius *= 1 + percent / 100 class BridgePattern: @staticmethod def test(): shapes = [ CircleShape(1.0, 2.0, 3.0, DrawingAPI1()), CircleShape(5.0, 7.0, 11.0, DrawingAPI2()), CircleShape(5.0, 4.0, 12.0, DrawingAPI3()), ] for shape in shapes: shape.resize_by_percentage(2.5) print(shape.draw()) BridgePattern.test() 削除されたパターン Bridgeパターン
  • 27. 削除されたパターン import java.util.*; abstract class Logger { public static final int ERROR = 3; public static final int NOTICE = 5; public static final int DEBUG = 7; private final int mask; protected Logger(int mask) { this.mask = mask; } // The next element in the chain of responsibility protected Logger next; public Logger setNext(Logger l) { next = l; return this; } public void message(String msg, int priority) { if (priority <= mask) { writeMessage(msg); if (next != null) { next.message(msg, priority); } } } abstract protected void writeMessage(String msg); } Chain of responsibilityパターン Chain of Responsibility パターン https://ja.wikipedia.org/wiki/Chain_of_Responsibility_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
  • 28. class StdoutLogger extends Logger { public StdoutLogger(int mask) { super(mask); } @Override protected void writeMessage(String msg) { System.out.println("Writting to stdout: " + msg); } } class EmailLogger extends Logger { public EmailLogger(int mask) { super(mask); } @Override protected void writeMessage(String msg) { System.out.println("Sending via email: " + msg); } } class StderrLogger extends Logger { public StderrLogger(int mask) { super(mask); } @Override protected void writeMessage(String msg) { System.out.println("Sending to stderr: " + msg); } } 削除されたパターン Chain of responsibilityパターン
  • 29. public class ChainOfResponsibilityExample { public static void main(String[] args) { // Build the chain of responsibility final Logger l = new StdoutLogger(Logger.DEBUG).setNext( new EmailLogger(Logger.NOTICE).setNext( new StderrLogger(Logger.ERROR))); // Handled by StdoutLogger l.message("Entering function y.", Logger.DEBUG); // Handled by StdoutLogger and EmailLogger l.message("Step1 completed.", Logger.NOTICE); // Handled by all three loggers l.message("An error has occurred.", Logger.ERROR); } } 削除されたパターン Chain of responsibilityパターン
  • 31. 削除されたパターン class Originator class Memento def initialize(state) @state = state.dup end def state @state.dup end end attr_accessor :state def save_to_memento Memento.new(@state) end def restore_from_memento(m) @state = m.state end end describe Originator do before(:all) do @caretaker = Caretaker.new @originator = Originator.new @originator.state = "State1" end it "should have original state" do @originator.state.should == 'State1' end it "should update state" do @originator.state = "State2" @originator.state.should == 'State2' end it "should save memento" do @caretaker << @originator.save_to_memento @caretaker.size.should == 1 end 以下略 Mementoパターン Memento パターン https://ja.wikipedia.org/wiki/Memento_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
  • 32. 削除されたパターン Observerパターン 1 対 多 の関係 オブジェクトの変化があったとき、依存するすべてのオブジェクトへ通知される ● サブジェクト: 通知するひと ● オブザーバー: 通知を受け取るひと 実装としては、サブジェクトに登録しておいたメソッドを順に呼び出すだけ。同期処理です。 非同期処理の場合は「イベント」や「メッセージ」などと呼んで区別することもあるらしい。
  • 33. 削除されたパターン Observerパターン Observer pattern https://en.wikipedia.org/wiki/Observer_pattern class Observable: def __init__(self): self._observers = [] def register_observer(self, observer): self._observers.append(observer) def notify_observers(self, *args, **kwargs): for obs in self._observers: obs.notify(self, *args, **kwargs) class Observer: def __init__(self, observable): observable.register_observer(self) def notify(self, observable, *args, **kwargs): print("Got", args, kwargs, "From", observable) subject = Observable() observer = Observer(subject) subject.notify_observers("test", kw="python")
  • 34. 追加されたパターン ● Dependency Injection ● Type Object ● Null Object ● Extension Object
  • 36. class Client { private $service; public function __construct(Service $service) { $this->service = $service; } public function doSomething() { $this->service->doSomething(); } } class Service { public function doSomething() { } } class Client { private $service; public function __construct() { $this->service = new Service(); } public function doSomething() { $this->service->doSomething(); } } class Service { public function doSomething() { } } 追加されたパターン Dependency Injectionパターン やはりあなた方のDependency Injectionはまちがっている。 http://blog.a-way-out.net/blog/2015/08/31/your-dependency-injection-is-wrong-as-I-expected/ DIパターン DIパターンでない
  • 38. 追加されたパターン Type Objectパターン class TypeObject def initialize(name, value) @name = name @value = value end def get(name) return @value end end def main(argv) t1 = TypeObject.new("a", "AAAA") t2 = TypeObject.new("b", "BBBB") puts(t1.get("a")) puts(t2.get("b")) end main(ARGV)
  • 39. 追加されたパターン Null Objectパターン 何もしないオブジェクト 0 と 1 を同一視する Null だったらこうする、という条件分岐をオブジェクトへ分離する
  • 40. 追加されたパターン Null Objectパターン Employee e = DB.getEmployee("Bob"); if(e != null && e.isTimeToPay(today)) e.pay() Employee e = DB.getEmployee("Bob"); if(e.isTimeToPay(today)) e.pay() 「アジャイルソフトウェア開発の奥義」pp. 243-246 Null Objectパターンでない Null Objectパターン
  • 42. 追加されたパターン Extension Objectパターン class BOM def initialize @ext ||= {} end def add(name, ext) @ext[name] = ext end def get(name) return @ext[name] end end def toXML return "XML" end def toCSV return "CSV" end def main(argv) bom = BOM.new bom.add("XML", toXML) bom.add("CSV", toCSV) puts(bom.get("XML")) puts(bom.get("CSV")) end main(ARGV) 例: 部品一覧を扱うクラスがある。このクラスに XML や CSV へ出力する機能を追加したい。 toXML や toCSV というメソッドを追加する手もあるが、 単一責任の原則(SRP)に反する。