SlideShare ist ein Scribd-Unternehmen logo
1 von 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)に反する。

Weitere ähnliche Inhalte

Was ist angesagt?

ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計Yoshinori Matsunobu
 
Java EE から Quarkus による開発への移行について
Java EE から Quarkus による開発への移行についてJava EE から Quarkus による開発への移行について
Java EE から Quarkus による開発への移行についてShigeru Tatsuta
 
データベース設計徹底指南
データベース設計徹底指南データベース設計徹底指南
データベース設計徹底指南Mikiya Okuno
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!mosa siru
 
A5 SQL Mk-2の便利な機能をお教えします
A5 SQL Mk-2の便利な機能をお教えしますA5 SQL Mk-2の便利な機能をお教えします
A5 SQL Mk-2の便利な機能をお教えしますester41
 
async/await のしくみ
async/await のしくみasync/await のしくみ
async/await のしくみ信之 岩永
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなKentaro Matsui
 
ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計sairoutine
 
ドメイン駆動設計 ~ユーザー、モデル、エンジニアの新たな関係~
ドメイン駆動設計 ~ユーザー、モデル、エンジニアの新たな関係~ドメイン駆動設計 ~ユーザー、モデル、エンジニアの新たな関係~
ドメイン駆動設計 ~ユーザー、モデル、エンジニアの新たな関係~啓 杉本
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろうKota Mizushima
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)Yoshitaka Kawashima
 
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Springドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring増田 亨
 
Riverpodでテストを書こう
Riverpodでテストを書こうRiverpodでテストを書こう
Riverpodでテストを書こうShinnosuke Tokuda
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門増田 亨
 
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法Tetsutaro Watanabe
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxShota Shinogi
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門大樹 小倉
 
ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方増田 亨
 
Bitbucketを活用したコードレビュー改善事例
Bitbucketを活用したコードレビュー改善事例Bitbucketを活用したコードレビュー改善事例
Bitbucketを活用したコードレビュー改善事例Kosuke Ito
 

Was ist angesagt? (20)

ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
 
Java EE から Quarkus による開発への移行について
Java EE から Quarkus による開発への移行についてJava EE から Quarkus による開発への移行について
Java EE から Quarkus による開発への移行について
 
データベース設計徹底指南
データベース設計徹底指南データベース設計徹底指南
データベース設計徹底指南
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
A5 SQL Mk-2の便利な機能をお教えします
A5 SQL Mk-2の便利な機能をお教えしますA5 SQL Mk-2の便利な機能をお教えします
A5 SQL Mk-2の便利な機能をお教えします
 
async/await のしくみ
async/await のしくみasync/await のしくみ
async/await のしくみ
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
 
ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計
 
ドメイン駆動設計 ~ユーザー、モデル、エンジニアの新たな関係~
ドメイン駆動設計 ~ユーザー、モデル、エンジニアの新たな関係~ドメイン駆動設計 ~ユーザー、モデル、エンジニアの新たな関係~
ドメイン駆動設計 ~ユーザー、モデル、エンジニアの新たな関係~
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Springドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
 
Riverpodでテストを書こう
Riverpodでテストを書こうRiverpodでテストを書こう
Riverpodでテストを書こう
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
 
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法
 
Mavenの真実とウソ
Mavenの真実とウソMavenの真実とウソ
Mavenの真実とウソ
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方
 
Bitbucketを活用したコードレビュー改善事例
Bitbucketを活用したコードレビュー改善事例Bitbucketを活用したコードレビュー改善事例
Bitbucketを活用したコードレビュー改善事例
 

Ähnlich wie 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
 
クロージャデザインパターン
クロージャデザインパターンクロージャデザインパターン
クロージャデザインパターンMoriharu Ohzu
 
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
 

Ähnlich wie 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
 

Mehr von 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
 

Mehr von 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)に反する。