iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 16
1

建立一本書處理物件

export class OneBookChainForSale extends ChainForSale {
  getDiscount(books: number): number {
    if (books == 1) {
      return 1;
    }
    return super.getDiscount(books);
  }
}
  • 每一個處理物件可以自己決定要不要處理
  • 處理物件可透過 super.getDiscount 方法, 傳遞給下一個處理物件(Class)

建立2,3,4,5 本書處理物件和更多的處理物件

export class TowBookChainForSale extends ChainForSale {
  getDiscount(books: number): number {
    if (books == 2) {
      return 0.95;
    }
    return super.getDiscount(books);
  }
}

export class ThreeBooksChainForSale extends ChainForSale {
  getDiscount(books: number): number {
    if (books == 3) {
      return 0.9;
    }
    return super.getDiscount(books);
  }
}

export class FourBooksChainForSale extends ChainForSale {
  getDiscount(books: number): number {
    if (books == 4) {
      return 0.8;
    }
    return super.getDiscount(books);
  }
}

export class FiveBooksChainForSale extends ChainForSale {
  getDiscount(books: number): number {
    if (books == 5) {
      return 0.75;
    }
    return super.getDiscount(books);
  }
}

export class MoreThanFiveBooksChainForSale extends ChainForSale {
  getDiscount(books: number): number {
    if (books >= 6) {
      return 0.75;
    }
    super.getDiscount(books);
  }
}

最後在getPrice 方法中, 建立一群處理物件

class Bookstore {
   getPrice(books: number): number {
      let more = new MoreThanFiveBooksChainForSale(null);
      let five = new FiveBooksChainForSale(more);
      let four = new FourBooksChainForSale(five);
      let three = new ThreeBooksChainForSale(four);
      let two = new TowBookChainForSale(three);
      let sale = new OneBookChainForSale(two);

      return books * 100 * sale.getDiscount(books);
   }
}

原本的if else 消失了, 透過 sale 串起來了.

結論

責任鏈模式帶有一點點裝飾者(Decorator) 的味道, 以及Template Method 的味道, 而初始化那一整塊處理物件, 也可以再透過其他方式來封裝. 另外同樣的 swicth case 也可以用這方式消滅.

不是所有的if else / switch case 一律都需要透過物件多型或責任鏈模式來解決, 但不可否認的, 如果每個條件(if 或是 case) 裡面要做的事情邏輯非常複雜, 而且這樣的條件, 那麼物件多型或責任鏈模式會很適合用的.

更重要的是責任鏈的用意在於每一個處理物件, 只知道自己本身的"責任" 並做自己應該做的事情, 不是本身的責任, 就丟給下一個處理物件.

單例模式 (Singleton)

大部分新手容易把 static 和 singleton 混繞, 因為兩者使用方式相似. static 是為了全域所有物件/函式都能夠直接存取用的. singleton 則是為了表明全域資源中只有這 "一份" 的意思, 表明資源唯一性.

單例模式(singleton) 是一種常用的軟體設計模式, 應用這個模式時, 必須保證只有一個實例存在. 使用時也要注意多執行緒(Multi-thread)之下的處理.

但幸好Javascript 是單執行緒語言, 瀏覽器無論在什麼時候都只有一個線程在運行Javascript , 瀏覽器中的多執行緒非同步是模擬出來的, 它是通過事件迴圈(Event loop) 加上任務佇列(Task Queue) 來實現的.

所以我們在Typescript 設計Singleton 模式的時候, 不必像C# 要考慮lock 問題.

下面是Typescript 典型的單例模式物件

class Singleton {
   private static instance: Singleton;
   private constructor() {
      // do something ...
   }
   
   static getInstance() {
     if( !Singleton.instance ) {
       Singleton.instance = new Singleton();
     }
     return Singleton.instance;
   }
}

使用的時候只需要這樣用

let obj = Singleton.getInstance();

但你如果嘗試這樣使用

let obj = new Singleton();

VSCode 編輯器會馬上告知你錯誤

Constructor of class 'Singleton' is private and only accessible within the class declaration.

如此一來可以避免其他開發人員誤用建立這個Singleton 物件. Typescript 好威阿!


上一篇
利用抽象類別取代if else - 15
下一篇
狀態模式(State Pattern) - 17
系列文
為什麼世界需要Typescript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言