顯示具有 design pattern 標籤的文章。 顯示所有文章
顯示具有 design pattern 標籤的文章。 顯示所有文章

2022年2月1日 星期二

[Geroge]設計模式-策略模式Strategy Pattern

策略模式定義了一系列的算法, 並將每一個算法封裝起來, 而且使他們還可以相互替換, 策略模式讓算法獨立於使用它的客戶而獨立變化

解決問題:

讓算法和對向分開, 使得算法可以獨立於使用它的客戶而變化

當存在以下情況使用Strategy模式

1 許多相關的類僅僅是行為有異, "策略"提供了一種用多個行為中的一個行為來配置一個類的方法, 即一個系統需要動態地在幾種算法中選擇一種

2 需要使用一個算法不同的實體, 例如, 你可能會定義一些反應不同空間/時間權衡的算法, 當這些變體實現為一個算法的類層次時, 可以使用策略模式

3 算法使用客戶不應該知道的數據, 可使用策略模式以避免暴露複雜的, 與算法相關的數據結構

4 一個類定義了多種行為, 並且這些行為在這個類的操作中以多個條件語句的形式出現, 將相關的條件分支移入它們各自的Strategy類中以代替這些條件語句






環境類(Context): 用一個ConcreteStrategy對象來配置, 維護一個對Strategy對象的引用, 可定義一個介面來讓策略類訪問它的數據

抽象策略類(Strategy): 定義所有支持的算法的公共介面, Context使用這個介面來調用某具體Strategy的定義算法

具體策略類(Concrete Strategy): 以Strategy介面實現某具體算法

例子:

我們有一個人要去旅行, 我們定義抽象介面旅行












這時, 旅行可以用不同種策略達到, 可以用走的, 搭火車的, 搭飛機的













這時候, 我們使用不同的策略, 只需要抽換介面的實現類, 在構造函數中傳入就可以運行了, 每當增加新的策略時, 不用改變Person和Travel中的任何程式碼








優點:

1 相關算法系列Strategy類層次為Context定義了一系列可供重用的算法或行為, 繼承有助於析取出這些算法中的公共功能

2 將算法封裝在獨立的Strategy類中使得你可以獨立於其Context改變它, 使它易於切換, 易於理解, 易於擴展

3 消除了一些if else 條件語句: Strategy模式提供了用條件語句選擇所需的行為以外的另一種選擇, 當不同行為堆砌在一個類中時, 很難避免使用條件語句來選擇合適行為, 將行為封裝在一個個獨立的Strategy類中消除了這些條件語句, 含有許多條件語句的程式碼, 通常意味著需要使用Strategy模式

4 實現的選擇Strategy模式可以提供相同行為的不同實現, 客戶可以根據不同時間/空間權衡取捨要求從不同策略中進行選擇


缺點:

1 客戶端必須知道所有的策略類, 並自行決定使用哪一個策略類, 可以結合工廠模式來克服這個問題

2 增加Strategy和Context之間的通信開銷, Strategy和Context之間進行更緊密的耦合

3 策略模式將造成產生很多策略類

https://www.youtube.com/watch?v=cA-vt0Nf1nQ&list=PLGmd9-PCMLhb16ZxeSy00qUsBazXgJyfM&index=21

https://github.com/iw5420/geroge-design-pattern

[Geroge]設計模式-觀察者模式Observer Pattern (下)

推模式

被觀察者對象向觀察者推送主題的詳細信息, 不管觀察者是否需要, 推送的信息通常是主題對象的全部或部分數據, 一般這種模型的現實中, 會把被觀察者對象中的全部或部分信息通過update的參數傳遞給觀察者 update(Object obj)

拉模式

被觀察者在通知觀察者的時候, 只傳遞少量信息, 如果觀察者需要更具體的信息, 由觀察者主動到被觀察者對象中獲取, 相當於是觀察者從被觀察者中拉數據

一般這種模型的實現中, 會把被觀察者對象自身通過update方法傳遞給觀察者update(Subject subject)這樣在觀察者需要獲取數據的時候, 就可以通過這個引用來獲取了

例子:

推模式

就是會推送信息, 我們就先造出信息類Weather, 用來放溫度和濕度











觀察者抽象類, update時傳送信息Weather物件






而subject實體類, 就是氣象站, 這裡當溫度或濕度改變的時候
我們必須產生Weather物件當作信息, 推送給觀察者








推送, 就是向已經註冊在列表中的觀察者, 去進行update並把Weather信息傳過去










觀察者物件被調用update時, 就會依照傳過來的Weather進行反應











這是整體進行的程式碼, 過程中看不到Weather物件, 是因為設置傳送Weather物件都在內部進行
















拉模式
相當於說觀察者更新的時候, 是傳送real subject過去, 就是傳氣象站過去




老王和小李則是獲得Weather Station對向作判斷















那我們Weather Station也會發生變化, 就是推送它自己了, 而不是Weather物件











當它改變溫度或濕度的時候, 我們只要調用notifyObserver()






重述一下拉模式重點

首先, 我們的Subject中的notifyObserver就不用傳訊息物件過去

另外我們的Observer類別需要傳Subject實體類過去















兩種模式的對比

推模式

優點: 很好保護了subject 降低觀察者與具體subject的耦合度

缺點: 當變化的參數繁多的時候, 觀察者將收到大量無關信息

拉模式

優點: 變化時對觀察者根據需要去取相應數據

缺點: 觀察者與具體subject的耦合度大大增加

https://www.youtube.com/watch?v=cA-vt0Nf1nQ&list=PLGmd9-PCMLhb16ZxeSy00qUsBazXgJyfM&index=20

https://github.com/iw5420/geroge-design-pattern


[Geroge]設計模式-觀察者模式Observer Pattern (上)

觀察者模式 Observer Pattern

有時候又被稱為 Publish-Subscribe模式(發布訂閱), 模型-視圖(View)模式, 源-收聽者(Listener)模式或從屬者模式, 是軟體設計模式的非常常見一種, 定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時, 所有依賴於它的對象都得到通知並被自動更新, 此種模式通常被用來實現事件處理系統







抽象主題角色(subject): 把所有對觀察者對象的飲用保存在一個集合中, 每個抽象主題角色都可以有任意數量的觀察者, 抽象主題提供一個介面, 可以增加和刪除觀察者角色, 一般用一個抽象類和介面來實現

抽象觀察者角色(observer): 為所有具體的觀察者定義一個介面, 在得到主題的通知時更新自己

具體主題角色(concrete subject): 在具體主題內部狀態改變時, 給所有登記過的觀察者發出通知, 具體主題角色通常使用一個子類實現

具體觀察者角色(concrete observer): 該角色實現抽象觀察者角色所要求的更新接口,以便使本身狀態與主題的狀態相協調, 通常用一個子類實現, 如果需要, 具體觀察者角色可以保存一個指向具體主題角色的引用

觀察者模式解決的問題

觀察者模式作為一種設計模式, 就是一種解決問題的方案, 也可以講是一個模板, 方法, 目的就是已通知代替輪詢: 當被觀察者狀態發生改變時, 會觸發觀察者發生改變

解耦觀察者與被觀察者的實現, 觀察者和被觀察對象之間的互動關係不能體現成類之間的直接調用, 否則就將使觀察者和被觀察對象之間緊密的耦合起來, 從根本上違反面向對象的設計原則, 無論是觀察者觀察對象, 還是被觀察者將自己的改變通知觀察者, 都不應該直接調用

例子:

首先先造 觀察者 和 主題角色 的抽象類

觀察者, 會依照觀察狀態而改變

主題角色, 會註冊觀察者, 移除觀察者, 通知觀察者








然後我們在具體主題角色(氣象站)中

有觀察者列表, 其中有註冊觀察者, 移除觀察者和通知觀察者

也有觀察變量, 溫度及濕度, 在變量改變的時候調用通知觀察者

而通知觀察者裡面的方法, 是將註冊在列表中的觀察者一一進行更新的調用














那我們需要觀察者的具體對象, 對變量改變的時候進行反應
















然後運行, 我們先New 出氣象站, 老王, 小李

然後將老王和小李註冊到氣象站中

當溫度或濕度變化的時候, 讓氣象站主動去通知老王和小李






讓氣象站通知老王跟小李就是下面這段程式碼作用











詳細運作, 假設當溫度改變的時候

進行邏輯為: 

氣象站設置溫度>

將註冊列表中的對象更新>

更新中對持有的氣象站進行變量判斷, 若是濕度超過則繼續進行邏輯

https://www.youtube.com/watch?v=cA-vt0Nf1nQ&list=PLGmd9-PCMLhb16ZxeSy00qUsBazXgJyfM&index=19

https://github.com/iw5420/geroge-design-pattern

2022年1月30日 星期日

[Geroge]設計模式-適配器模式Adapter Pattern (下)

 2對象的適配器







與類的適配器模式一樣, 對象的適配器模式把被適配的淚的API轉換成為目標類的API, 與類的適配器模式不同的是, 對象的適配器模式不是使用繼承關係連接到Adaptee類, 而是使用委派關係連接到Adaptee的實例, 從而包裝類能夠把Adaptee的API與Target類的API銜接起來, Adapter與Adaptee是委派關係, 這決定了適配器模式是對象的(相當於Adapter把Adaptee當作成員, 並調用Adaptee做額外特別的處理)

例子:




有220V也有12V

我們將220V當作成員變數放在Adapter中

履行12V的方法, 並在其中呼叫220V並使用轉換














下面是運作類, 先New notbook, 再new Adapter將220V放入, 最後notebook使用Adapter 來turn on





下方是結果




對象與類適配器對比1

類適配器使用對象繼承方式, 是靜態的定義方式(啟動時動作)

對象適配器使用對象組合的方式, 是動態組合的方式(運作時動作)

對象與類適配器對比2

類適配器, 由於Adapter直接繼承Adaptee ,使得Adapter不能和Adaptee的子類一起工作, 因為繼承是靜態關係, 當Adapter繼承了Adaptee後, 就不可能去處理Adaptee的子類了

對象適配器, 一個Adapter可以把多種不同的源是配到同一個目標, 換言之, 同一個適配器可以把源類和它的子類都是配到目標接口, 因為對象適配器採用的是對象組合的關係, 只要對象類型正確, 是不是子類都無所謂

對象與類適配器對比3

類適配器, Adapter可以重新定義Adaptee的部分行為, 相當於子類可以覆蓋父類的部分實現方法

對象適配器, 要重新定義Adaptee的行為比較困難, 這種情況下, 需要定義Adaptee的子類來重新實現定義, 然後讓適配器組合子類, 雖然重定義Adaptee行為比較困難, 但是想要增加一些新的方法相當方便,而且新增行為可同時適用於所有的源

對象與類適配器對比4

對於類適配器, 僅僅引入了一個對象, 並不需要額外的引用來間接得到Adaptee

對於對象適配器, 需要而外的引用來間接得到Adaptee


使用建議:

建議盡量使用對象適配器的實現方式, 多用合成/聚合, 少用繼承, 當然具體問題具體分析, 根據需要來選擇實現方是, 最適合的才是最好的


適配器模式的優點:

更好的復用性: 系統需要使用現有的類, 而此類的介面不符合系統的需要, 那麼通過適配器模式就可以讓這些功能得到很好的復用

更好的擴展性: 在實現適配器功能的時候, 可以調用自己開發的功能, 從而自然地擴展系統的功能


適配器模式的缺點:

過多使用適配器, 會使系統非常凌亂, 不容易整體把握, 例如明明看到調用A介面, 但是內部被配適成B介面, 一個系統如果出現太多這種情況, 無疑是種災難, 因此如果不是必要, 可以不使用是珮配器, 而是直接對系統進行重構


實際使用場景:

一般是外部提供的庫, 或是包, 定義介面與方法不同於本系統內部定義的介面

為了不改變本系統內部調用的流程, 往往使用適配器模式來間容外部提供的褲或包

https://www.youtube.com/watch?v=cA-vt0Nf1nQ&list=PLGmd9-PCMLhb16ZxeSy00qUsBazXgJyfM&index=18

https://github.com/iw5420/geroge-design-pattern


[Geroge]設計模式-適配器模式Adapter Pattern (上)

適配器模式(Adapter pattern)

將一個類的介面轉換成客戶希望的另外一個介面, Adapter模式使得原本由於介面不兼容而不能一起工作的那些類可以一起工作-Gang of Four

就如同筆記本的插頭一般都會帶有一個黑色長方形的物體, 名字叫適配器(轉接頭)

功能就把220V轉化為12V供我們的筆記本使用, 我們今天講的模式是一樣的





適配器模式的結構 有兩種:

1類的適配器模式









Adapter是中間一個環節, 把Adaptee的API與Target類的API銜接起來

Adapter繼承Adaptee同時實現Target介面(因繼承而屬於類的適配器模式)

目標(Target)角色: 這就是期待的介面, 由於這裡是類適配器模式, 因此目標不可以是類

源(Adaptee)角色: 現在需要適配的對象(ex 220V)

適配器(Adapter)角色: 類適配器適本模式的核心, 類適配器把源類別轉換成目標介面, 顯然這一角色不可以是介面, 而必須是具體類

例子:

我們有220V, 也有5V, 而NoteBook使用5V做事










這時我們就需要轉接頭(Adapter)

運作getPower5V裡面會使用父類別得到220V並轉換






運作測試, 當notbook power on的時候塞入Adapter






下面是結果




https://www.youtube.com/watch?v=cA-vt0Nf1nQ&list=PLGmd9-PCMLhb16ZxeSy00qUsBazXgJyfM&index=17

https://github.com/iw5420/geroge-design-pattern


2022年1月27日 星期四

[Geroge]設計模式-Java動態代理

靜態代理: 自己手寫的代理類, 程序運行前就已經存在的編譯好的代理類 by Geroge

反之~如果代理類程序運行之前並不存在, 需要在程序運行時動態生成(無須手工編寫代理類源碼), 那就是今天要說的動態代理了

如何生成的: 根據Java的反射機制動態生成

*****

Java動態代理(Dynamic Proxy)

在java中, 通常使用Proxy(動態代理)來實現對代理模式的支持

Java中要創建一個代理對象, 必須調用Proxy類的靜態方法newProxyInstance,該方法的原型如下

Object Proxy.newProxyInstance(ClassLoader loader, class<?>[]interfaces, InvacationHandler handler) throws IllegalArgumentExcetion

其中: 

loader: 表示類加載器, 對於不同來源(系統庫或網路等)的類需要不同的類加載器來加載, 這是Java安全模型的一部分

interfaces: 它就是被代理對象共有的介面

handler : 表示調用處理器, 它必須是實現了InvocationHandler介面的對象, 其作用是定義代理對象中需要執行的具體操作, InvocationHandler 之於Proxy, 就如Runnable之於Thread, InvocationHandler 介面中只有一個方法Invoke, 它的作用就跟Runnable中的run方法類似, 定義了代理對象在執行真實對象的方法時所希望執行的動作, 其原型如下:

Object invoke(Object proxy, Method method, Object[] args)throws Throwable

其中

proxy: 表示執行這個方法的代理對象

method: 表示真實對象實際需要執行的方法(關於Method類參見Java的反射機制)

args: 表示真實對象實際執行方法時所需的參數

例子: 

例如我們有一個KFC介面, 還有它的實現, 也有miseller介面, 和它的實現



















我們造一個Handler類別去實行InvocationHandler類別
生一個區域變數realObject, 當初始化時傳進來
下面方法調用invoke的時候它再invoke找realSubject做事










而它在使用上, 可以用Proxy. newProxyInstnce傳入當前class.getClassLoader, 第二個參數有兩種寫法如下new Class[]{將使用的介面}, 或是將使用的介面.class.getInterfaces(), 最後再new ProxyHandler類別出來將要使用的實現類別塞入




















總結
Proxy已經設計優美, 但是它有小缺憾, 始終無法擺脫interface代理, 基於代理他們已經注定有一個共同父類Proxy, 這個機制注定了動態代理類無法對class的動態代理, 原因是多重繼承無法通行
那類的動態代理有CGLib, Aspectj可以再更深入學習

https://www.youtube.com/watch?v=cA-vt0Nf1nQ&list=PLGmd9-PCMLhb16ZxeSy00qUsBazXgJyfM&index=16

https://github.com/iw5420/geroge-design-pattern


2026半年度目標

 1 每個月看看能不能都做專案, 一年12專案 2 刷題每周4題 3 跑個人scrum, 並組讀書會 4規律讀英文ex每天早上8:30-9:30 5規律運動7:35-8:30 6減肥97->85 這是今年年初的目標, 有刷一點題, 但是差不多三月初AI大爆發, 不得不開始接...