動的なデザインパターン 不確定な多様性の状況下の適応性設計 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. 2013 Stephen Wang
Tweet This Book! Please help Stephen Wang by spreading the word about this book on Twitter! 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: https://twitter.com/search/#
Contents 感謝................................................. 1 紹介................................................. 2 第 1 節最適化パターン........................................ 4 延長読み............................................... 16
感謝 下記はこの本の編集に助けて頂いた人のリストである 李小波 大変ありがとうございました 私の家族にも感謝します 彼らのサポートがない限り この本の出版はできません この本は デザインパターン ¹ を参考しました ¹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 } 16 }
第 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 } 13 }
第 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; 2 3 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 } 9 }
第 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 } 12 }
第 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) 32 List<Book> onecopy = new ArrayList<Book>();
第 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) { 74 if (hasbook(book)) {
第 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 } 116 if (hasbook(bookflyweight.book_5)) {
第 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; 20 }
第 1 節最適化パターン 14 21 22 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>(); 15
第 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 } 上記のソースの実行結果が以下となる : 51.2
延長読み プールパターン (Pool Pattern) 有限サイズのプールよりオブジェクトをアクセスするパターン ポリシーパターン (Policy Pattern) プロセスではなく ポリシーに従い処理を行うパターン パネルパターン (Panel Pattern) スイッチのパネルに ON/OFF を整理するパターン ディスパッチャーパターン (Dispatcher Pattern) 事前に定義したルールに従い リクエストをインスタンスに配布する コーオーディネーターパターン (Coordinator Pattern) グローバル条件の下で サブジェクトを調整するパターン 動的なアダプターパターン (Dynamic Adapter Pattern) 条件により Adapter を変えるパターン 動的なコマンドパターン (Dynamic Command Pattern) The pattern to execute commands in context.