動的なデザインパターン
不確定な多様性の状況下の適応性設計
Stephen Wang
This book is for sale at
http://leanpub.com/dynamic_design_patterns_jp
This version was published on 2013-08-22
This is a
Leanpub
book. Leanpub empowers authors and publishers with the Lean Publishing
process.
Lean Publishing
is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
Tweet This Book!
Please help Stephen Wang by spreading the word about this book on
!
The suggested hashtag for this book is
#
デザインパターン.
Find out what other people are saying about the book by clicking on this link to search for this
hashtag on Twitter:
Contents
感謝
. . . .
1
紹介
. . . .
2
第
1
節最適化パターン. . . .
4
感謝
下記はこの本の編集に助けて頂いた人のリストである。 李小波 大変ありがとうございました。 私の家族にも感謝します。彼らのサポートがない限り、この本の出版はできません。 この本は「デザインパターン¹
」を参考しました。 ¹http://en.wikipedia.org/wiki/Design_Patterns紹介
多様性 ソフトウェアが多様な機能があるので、不同なユーザーが不同なデータをアクセスさせられ る。オブジェクト指向がソフトウェアの多様性を実現できる技術の一種である。システムで は複数の操作が統一インターフェースを共有することもあるし、複数のデータが同一フィー ルドを共有することもある。オブジェクト指向技術がインターフェースとクラスの定義でこ の多様性を実現させられる。ところが、最近、ソフトウェアがもっと多様化になってきて、 プログラミングがもっと複雑になる。これらの多様性がプロセスが不確定で、ルールのみ定 義される状況で起こしたのである。ルールしか従えないプログラミングが不確定性を実現で きる。 不確定性•
娯楽 ゲームでは、不確定性が娯楽のともとなる。ランダムナンバーだけでなく、条件の多様性も 不確定性を起こす。•
ビジネス ビジネスのルールがよく変わる、ソフトウェアがこれらのリクエアメントを対応するため の拡張性が必要。自動的に適応なら希望される。•
個性的 インターネットの時代では、ユーザーが使っている個性化したいので、オンラインサービス が個性化できるように作る必要。個性化がユーザーを喜ばせるが、技術上の挑戦も持ってく る。 オブジェクト指向技術は共通メソッドのシグネチャーを要求される。同一インターフェース から継承したメソッドが同一メソッドシグネチャーを共有する。但し、不確定の環境では、 処理がかなり不同なので、メソッドのシグネチャーを統一するのがとても難しい。この不確 定な環境を適応できるプログラミング技術が望ましい。 予測性紹介
3
不確定の多様な条件では、ルールが事前定義されるが、インスタンス、行為やデータが予測 できない。予測できる環境では、インターフェースを定義し、実装するなら、多様性をハン ドルできるが、予測できいない環境では、固定なインターフェースと処理を書けない。 動的なデザインパターン デザインパターンは多様性を処理できるが、多様性が不確定の場合は、デザインパターンだ けで対処できない。動的なデザインパターンはこの不確定の多様性な状況を対応する。その 名前で暗示するように、動的なデザインパターンはデザインパターンである、GoF
のデザイ ンパターンをベースにして、不確定性を対処できる機能を追加したのである。第
1
節最適化パターン
説明Chain of responsibility
パターン²
では、パラメーターを一連のクラスに渡して、各ステッ プはChain
の最後まで、パラメーターを処理する。 但し、Chain
が予測できない、事前定義できない場合は、事前に定義したルールに従って、 動的にハンドラーを作成し、退出条件が合うまで、連続的に、ハンドラーを呼ぶ。 これがストレージを最適化するパターンなので、’最適化パターン’だと呼ぶ。UML
最適化パターンのUML
は以下となる:
構造上のサンプル このサンプルが最適化パターンを説明し、退出条件が合うまで、動的にハンドラーを生成す る。 ²http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern第1節最適化パターン
5
• Handler
ハンドラーインターフェース。• HandlerFactory
ファクトリーが事前定義ルールに従い、動的にハンドラーを生成する。• ConcreteHandlerA, ConcreteHanlderB
プロセスを行う実装したハンドラー。• NullHandler
リクエストをダミーにハンドルのNull
オブジェクト。• Client
他のクラスをアクセスするクライアント。• Text
処理対象の集合。1 public interface Handler {
2 public Text handle(Text text);
3 }
1 public class HandlerFactory {
2
3 public static Handler create(String params) {
4 int aIndex = params.lastIndexOf("a");
5 int bIndex = params.lastIndexOf("b");
6 if (aIndex >= 0 || bIndex >= 0) {
7 if (aIndex > bIndex) {
8 return new ConcreteHandlerA();
9 } else {
10 return new ConcreteHandlerB();
11 }
12 } else {
13 return new NullHandler();
14 }
15 }
第1節最適化パターン
6
1 public class ConcreteHandlerA implements Handler {
2 public Text handle(Text text) {
3 int index = text.find("a");
4 return text.reduce(index);
5 }
6 }
1 public class ConcreteHandlerB implements Handler {
2 public Text handle(Text text) {
3 int index = text.find("b");
4 return text.reduce(index);
5 }
6 }
1 public class NullHandler implements Handler {
2 public Text handle(Text text) {
3 return text;
4 }
5 }
1 public class Client {
2 public void dynamicChain(Text text) {
3 while (text.hasMore()) {
4 Handler next = HandlerFactory.create(text.text);
5 next.handle(text);
6 }
7 }
8
9 public static void main(String[] args) {
10 Client client = new Client();
11 client.dynamicChain(new Text("aba2fdac23fabc"));
12 }
第1節最適化パターン
7
1 public class Text {
2 public String text;
3
4 public Text(String t) {
5 this.text = t;
6 }
7
8 public boolean hasMore() {
9 return !text.isEmpty();
10 }
11
12 public int find(String target) {
13 int index = text.lastIndexOf(target);
14 System.out.println(text.substring(index));
15 return index;
16 }
17
18 public Text reduce(int index) {
19 String reduced = "";
20 if (index > 0) {
21 reduced = text.substring(0, index);
22 } else { 23 reduced = ""; 24 } 25 text = reduced; 26 return this; 27 } 28 } 上記のソースの実行結果が以下となる
:
1 bc 2 a 3 ac23f 4 a2fd 5 b 6 a 現実中のサンプル ある本屋がシリーズの本にプロモーションを行うつもりがある。割引政策は以下となる。第1節最適化パターン
8
• 5
冊を買うなら,
75%,
• 5
冊の中任意不同な4
冊なら, 80%,
• 5
冊の中任意不同な3
冊なら, 90%,
• 5
冊の中任意不同な2
冊なら, 95%,
• 5
冊の中任意不同な1
冊なら, 100%,
各本の値段は全部8
ユーロである.
以下の組み合わせで本を買う場合、最低値段を計算してください。•
本#1 - 2
冊•
本#2 - 2
冊•
本#3 - 2
冊•
本#4 - 1
冊•
本#5 - 1
冊 このケースでは、最適化条件は事前定義されていない、但し、ルールが定義されている。多 ければ、多いほど本を選んだら、安くなる。だが、4
冊+4
冊なら、5
冊+3
冊より安い。 1 import java.util.List; 23 public interface CartStrategy {
4 public Cart handle(Cart cart, List<Strategy> strategies);
5 }
1 import java.util.List;
2
3 public class MostCartStrategy implements CartStrategy {
4 public Cart handle(Cart cart, List<Strategy> strategies) {
5 Strategy strategy = cart.pickMost();
6 strategies.add(strategy);
7 return cart;
8 }
第1節最適化パターン
9
1 import java.util.List;
2
3 public class SmartCartStrategy implements CartStrategy {
4 public Cart handle(Cart cart, List<Strategy> strategies) {
5 Strategy before = cart.pick4();
6 Strategy after = cart.pick4();
7 strategies.add(before);
8 strategies.add(after);
9 return cart;
10 }
11 }
1 import java.util.List;
2
3 public class NullCartStrategy implements CartStrategy {
4 public Cart handle(Cart cart, List<Strategy> strategies) {
5 return cart;
6 }
7 }
1 public class CartStrategyFactory {
2
3 public static CartStrategy create(Cart cart) {
4 if (cart.has44()) {
5 return new SmartCartStrategy();
6 } else if (!cart.isEmpty()) {
7 return new MostCartStrategy();
8 } else {
9 return new NullCartStrategy();
10 }
11 }
第1節最適化パターン
10
1 public class Book {
2 public String name;
3 public float price;
4
5 public Book(String n, float p) {
6 this.name = n; 7 this.price = p; 8 } 9 } 1 import java.util.*; 2
3 public class Cart {
4
5 Map<Book, Integer> books = new HashMap<Book, Integer>();
6
7 public void add(Book book, Integer count) {
8 if (books.containsKey(book)) {
9 books.put(book, books.get(book) + count);
10 } else {
11 books.put(book, count);
12 }
13 }
14
15 public boolean isEmpty() {
16 if (books.isEmpty()) {
17 return true;
18 }
19 Iterator iterator = books.keySet().iterator();
20 while (iterator.hasNext()) {
21 Book book = (Book) iterator.next();
22 if (books.get(book) != 0) {
23 return false; 24 } 25 } 26 return true; 27 } 28
29 public boolean has44() {
30 //44 = 53(5 different books, at least 3 of them is more than 2 copies) 31 //44 = 44 (4 different books, all are more than 2 copies)
第1節最適化パターン
11
33 List<Book> moreCopies = new ArrayList<Book>();34
35 Iterator iterator = books.keySet().iterator();
36 while (iterator.hasNext()) {
37 Book book = (Book)iterator.next();
38 Integer count = books.get(book);
39 if (count > 1) {
40 moreCopies.add(book);
41 } else {
42 oneCopy.add(book);
43 }
44 }
45
46 if (oneCopy.size() + moreCopies.size() == 5 && moreCopies.size() >= 3
47 || moreCopies.size() >= 4) { 48 return true; 49 } 50 51 return false; 52 } 53
54 public Strategy pick4() {
55 Strategy strategy = new Strategy();
56
57 if (countBookType() == 4) {
58 return pickMost();
59 } else {
60 Book least = findLeastBook();
61 for (Book book : BookFlyweight.books) {
62 if (hasBook(book) && !book.equals(least)) {
63 pickBook(strategy, book);
64 } 65 } 66 } 67 68 return strategy; 69 } 70
71 private int countBookType() {
72 int count = 0;
73 for (Book book : BookFlyweight.books) {
第1節最適化パターン
12
75 count ++;76 }
77 }
78 System.out.println("count = " + count);
79 return count;
80 }
81
82 private Book findLeastBook() {
83 int min = -1;
84 Book least = null;
85 Iterator keys = books.keySet().iterator();
86 while (keys.hasNext()) {
87 Book book = (Book)keys.next();
88 int count = books.get(book);
89 if (min == -1) { 90 min = count; 91 least = book; 92 } 93 if (min > count) { 94 least = book; 95 min = count; 96 } 97 } 98 return least; 99 } 100
101 public Strategy pickMost() {
102 Strategy strategy = new Strategy();
103
104 if (hasBook(BookFlyweight.BOOK_1)) {
105 pickBook(strategy, BookFlyweight.BOOK_1);
106 }
107 if (hasBook(BookFlyweight.BOOK_2)) {
108 pickBook(strategy, BookFlyweight.BOOK_2);
109 }
110 if (hasBook(BookFlyweight.BOOK_3)) {
111 pickBook(strategy, BookFlyweight.BOOK_3);
112 }
113 if (hasBook(BookFlyweight.BOOK_4)) {
114 pickBook(strategy, BookFlyweight.BOOK_4);
115 }
第1節最適化パターン
13
117 pickBook(strategy, BookFlyweight.BOOK_5);118 }
119
120 return strategy;
121 }
122
123 private boolean hasBook(Book book) {
124 if (books.containsKey(book)) {
125 if (books.get(book) == 0) {
126 return false; 127 } 128 return true; 129 } 130 return false; 131 } 132
133 private void pickBook(Strategy strategy, Book book) {
134 strategy.add(book);
135 books.put(book, books.get(book) - 1);
136 } 137 } 1 import java.util.HashMap; 2 import java.util.Iterator; 3 import java.util.Map; 4
5 public class Strategy {
6 Map<Book, Integer> books = new HashMap<Book, Integer>();
7
8 public void add(Book book) {
9 books.put(book, 1);
10 }
11
12 public String toString() {
13 String text = "";
14 Iterator iterator = books.keySet().iterator();
15 while (iterator.hasNext()) {
16 Book book = (Book)iterator.next();
17 text += book.name + "@" + books.get(book) + ",";
18 }
19 return text;
第1節最適化パターン
14
2122 public float price() {
23 float price = 0.0f;
24 Iterator iterator = books.keySet().iterator();
25 while (iterator.hasNext()) {
26 Book book = (Book)iterator.next();
27 price += book.price;
28 }
29 return price * discountRate();
30 }
31
32 public float discountRate() {
33 switch (books.keySet().size()) {
34 case 5: 35 return 0.75f; 36 case 4: 37 return 0.8f; 38 case 3: 39 return 0.9f; 40 case 2: 41 return 0.95f; 42 default: 43 return 1f; 44 } 45 } 46 } 1 import java.util.ArrayList; 2 import java.util.List; 3
4 public class Client {
5
6 public static void main(String[] args) {
7 Cart cart = new Cart();
8 cart.add(BookFlyweight.BOOK_1, 2);
9 cart.add(BookFlyweight.BOOK_2, 2);
10 cart.add(BookFlyweight.BOOK_3, 2);
11 cart.add(BookFlyweight.BOOK_4, 1);
12 cart.add(BookFlyweight.BOOK_5, 1);
13
14 List<Strategy> strategies = new ArrayList<Strategy>();
第1節最適化パターン
15
16 while (!cart.isEmpty()) {
17 CartStrategy strategy = CartStrategyFactory.create(cart);
18 cart = strategy.handle(cart, strategies);
19 }
20 float price = 0.0f;
21 for (Strategy strategy : strategies) {
22 System.out.println(strategy.toString());
23 price += strategy.price();
24 }
25 System.out.println("The amount is : " + price);
26 }
27 }
1 public class BookFlyweight {
2 public static final Book BOOK_1 = new Book("#1", 8);
3 public static final Book BOOK_2 = new Book("#2", 8);
4 public static final Book BOOK_3 = new Book("#3", 8);
5 public static final Book BOOK_4 = new Book("#4", 8);
6 public static final Book BOOK_5 = new Book("#5", 8);
7 }
上記のソースの実行結果が以下となる
:
延長読み
•
プールパターン(Pool Pattern)
有限サイズのプールよりオブジェクトをアクセスするパターン。•
ポリシーパターン(Policy Pattern)
プロセスではなく、ポリシーに従い処理を行うパターン。•
パネルパターン(Panel Pattern)
スイッチのパネルにON/OFF
を整理するパターン。•
ディスパッチャーパターン(Dispatcher Pattern)
事前に定義したルールに従い、リクエストをインスタンスに配布する。•
コーオーディネーターパターン(Coordinator Pattern)
グローバル条件の下で、サブジェクトを調整するパターン。•
動的なアダプターパターン(Dynamic Adapter Pattern)
条件により、