# 設計模式 (design pattern)(用作品前都必須要看)
大話設計
https://github.com/3masterplus/book/blob/master/%E5%A4%A7%E8%AF%9D%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F(%E5%B8%A6%E7%9B%AE%E5%BD%95%E5%AE%8C%E6%95%B4%E7%89%88).pdf
歐洲SOLID原則
https://www.youtube.com/watch?v=rtmFCcjEgEw
歐洲laravel
https://www.youtube.com/watch?v=qpo5KG0vIyE&t=358s
我們在開發功能的時候,都是讓大功能(高階模組)調用各個小功能(低階模組)來實現目標,越高層的就越整體、越抽象、越接近目標;而越低階就越細節、越接近實作,關注點越小。而我們的思維通常是由大範圍往下到小實作,從整體目標逐漸拆解成各個步驟。
**function 將概念封裝,將變數區域化**
https://www.youtube.com/watch?v=M7Xi1yO_s8E
簡單的了解(150元買的)
https://www.youtube.com/watch?v=W7N4XnZQF78
**不要用繼承 用組合**
https://www.thepolyglotdeveloper.com/2018/09/inheritance-composition-php-application/

https://www.koderhq.com/tutorial/php/oop-composition/
https://www.youtube.com/watch?v=nnwD5Lwwqdo
is-a 不好
要用 has-a
https://antrash.pixnet.net/blog/post/80808873
design pattern的前輩們帶來的忠告:多用合成、少用繼承
就是用依賴注入的方式 用組合
不要用繼承
## SOLID
https://www.youtube.com/watch?v=UQqY3_6Epbg&list=PLZlA0Gpn_vH9kocFX7R7BAe_CvvOCO_p9

### 單一原則大概都懂了
### 開放封閉原則 (Open-Close Principle)
https://igouist.github.io/post/2020/10/oo-11-open-closed-principle/
https://wadehuanglearning.blogspot.com/2019/12/blog-post_11.html
主要邏輯和附加邏輯,附加到主要邏輯
**心業務邏輯簡稱為「業務邏輯」。也就是說系統中有可能 20% 是業務邏輯,剩下的 80% 是圍繞著業務邏輯延伸出來的附加邏輯。
舉例來說,一個診所掛號系統一開始只有「掛號與叫號」功能。但若需要的話,也可以延伸出「叫號時發送簡訊提醒患者」功能。掛號系統的案例中業務邏輯是「掛號與叫號」;而「叫號時發送簡訊提醒患者」則是 隨著時間與新需求延伸出來的附加邏輯。**
**面對需求,對程式碼的改動是透過增加新程式碼進行的,而不是更改現有的程式碼
(《大話設計模式》)**
### 封閉擴充
if switch這些 都可以用擴充原則 因為他是之後要擴充 都要進去if 之類的做修改
這樣就不是擴充了(但小型的不用 不要過度使用設計模式)
https://igouist.github.io/post/2020/10/oo-11-open-closed-principle/
**凡是變化都有成本,**
其實你我都已經很習以為常了,就是**模組化**。
**實行**
在主要邏輯和附加邏輯之間,加入抽象層來解耦合 + 介面
使用外部注入來處理附加邏輯。除了不將附加邏輯寫在類別中,降低修改的機會以外,和介面的邏輯一致:你給什麼工具我就用什麼工具
有點像是package一樣 你可以對她擴充
你只會使用他 然後增加 但不會改動他
這樣一直擴充 就等於她一直被測試
所以增強他穩定性
例子

看起來沒問題 但當你要擴充呢

所以應該這樣寫

但動作一樣 所以要介面


所以controller應該這樣寫
裡面是上面那樣這樣才是工廠模式

簡單來說你new他然後做同樣的事情
所以你應該把new當成工廠
他每次做的都一樣 區分是type
所以每一種都是function 然後一樣動作用interface
這是工廠
外面再傳入type就好了
就是不更動的前提擴充
### 里氏替換原則 (Liskov Substitution Principle)
替換
這是最對object的原則了
用注入之類的 is-a 跟 has-a
https://igouist.github.io/post/2020/11/oo-12-liskov-substitution-principle/
**子類別替換父類別後,不需要改變,也不會發生任何錯誤或異常。**
**我們該如何遵守里氏替換原則?**
用子類別實作出各式各樣不同的方法,藉此讓父類別的方法藉此達到延伸和多樣化的效果」如此我們的物件彼此之間才能保持彈性,擁有可替換可擴充的特性,進而達到 開放封閉原則
**然而,這個擴展不該是天馬行空隨便亂擴的,必須要有原則**
最首要的就是:至少父類別能做到的事情,子類別也要能做到
一個好的擴展方式,應該能滿足這些條件:
* 要求不應該比父類別多
* 回饋不應該比父類別少
建議看文章上面的
**我們預期了這個函式或類別需要準備的輸入參數,也預期了應該要有的輸出結果。如果某一天替換了子類別,卻不是這麼一回事,就會發生很多意料外的錯誤**
就是父親有的他也要有,你可以想成是oredrByquery那個
複寫 但還是要有原本功能
但記得不要亂繼承
功能(行為)可以用has
真的需要在繼承
### 介面隔離原則
https://igouist.github.io/post/2020/11/oo-13-interface-segregation-principle/
簡單 就分細一點
**介面也要單一職責**
**但js不一樣可以看影片**
https://www.youtube.com/watch?v=JVWZR23B_iE&list=PLZlA0Gpn_vH9kocFX7R7BAe_CvvOCO_p9&index=4
### 依賴反轉原則
https://igouist.github.io/post/2020/12/oo-14-dependency-inversion-principle/
依賴
匯出報表」功能建立了一個「Excel 控制類別」的實例以建立檔案;或是「會員查詢」功能建立了一個「DB 連線」的實例來進入資料庫取得會員資料,諸如此類由A模組直接藉由B模組的實例來完成想要的動作,就是依賴。
依賴反轉的原理
中間要多一個

store 用 stripe付款
但可能改用別的paypel之類的
那你就用中間寫一個 負責付款的他可以接受不同付款的功能

https://igouist.github.io/post/2020/12/oo-14-dependency-inversion-principle/
高階模組不應該依賴於低階模組。兩者都應該依賴抽象
(建議看文章)
**依賴反轉最基本的思維路線。我們並不是用低階模組的功能直接拼湊出高階模組,讓高階模組直接依賴低階模組然後受到影響;而是把關注點放在需要的功能上,用介面隔開實作,解開他們彼此之間的耦合,介面就是模組之間的抽象層。**
簡單來說
就是公司repository一樣
方法都寫好了抽象方法
你去做
然後要改全部都會一起改
## 最少知識原則
五大原則中L位的第一候補:最少知識原則,也被稱作迪米特法則。
**不應該使用其他類別的方法所回傳的類別的方法。**
Foo.GetBoo().BooDoSomeThing() 這種情況,我們不該去跟 Foo 要 Boo 回來然後使用 Boo 的方法,因為我們只認識 Foo,而不認識 Boo。
## 設計模式—建造者模式 (Builder Design Pattern)
https://medium.com/wenchin-rolls-around/%E8%A8%AD%E8%A8%88%E6%A8%A1%E5%BC%8F-%E5%BB%BA%E9%80%A0%E8%80%85%E6%A8%A1%E5%BC%8F-builder-design-pattern-7c8eac7c9a7
## 分散式架構
分散式架構是指多個電腦 不是單一電腦那樣
多個資料庫 不是單一資料庫
防止single point Of Failure的風險
**分散式架構一定要小心資料一致性**
三大分類
運算
服務分流
儲存
## 設計模式必懂得 UML講解
組合

依賴關係



## 希望設計出來有的特性
**Scalabulity** 可拓展性/可縮短性
**Reliabiltity** 可靠性 系統無故障執行的概率
**Availbility** 可用性 系統不中斷運行時間占實際運行時間的比例

可用不一定可靠
可靠一定可用
**Effciency** 高效率
* latancy 延遲 執行一個操作要花費的時間長度
* Throughput 吞吐量 以一個時間區間作為單位 單位時間內可以執行幾次操作 或運算的次數
Manageability 可管理性(面對開發人員)
讓一個系統方面管理,ci/cd那種
能不能快速追蹤bug
快速把infrastructure(iac)抽象化
主要是讓開發人員能更專注在邏輯的運算上
## 必要技能
**前端 後端也要看**
cache
proxy
cdn
load Balancing
DataBase
DB master-slave
message queue
schema design
CAP Therem
partition & Sharding
Replication & Redundant

### cdn
就是一個分離式的概念
這樣要取東西不會去很遠的地方
不會要回應很久
他比較常存放靜態的 圖片的 東西
### cache
基本

在分散式系統很難
因為會有資料不同步情況
### load Balaning
多台主機那樣

有不同演算法
ex
round-robin
一二三依照下去
last Connected
看誰最有空
ip-Hash
每次經過同一個加密
所以以後都會給同一個主機
## 如何思考
**第一步**
釐清系統需求
兩大重點
function requirements
上傳照片邏輯之類的
non-function requeirements
上傳照片不會遺失,播放影片不會lag
**第二步**
關於系統流量 容器 網路頻寬的粗略計算
**第三步**
定義System interface
RESF API or GraphSQL
**第四步**
定義 Data Model | DB Schema
資料欄位那些
**第五步**
High Level Dsign
因為有前面幾步驟 知道具體流量跟資料庫等規範
這邊就能知道機台要不要水平擴展

這步驟有基本架構
**第六步**
System Detailed Design
更深入的設計
**第七步**
find trade Off and Try to Solve it
找到系統的缺點
然後說出自己的不足
### 以 Netflix 為例做系統規劃
https://www.youtube.com/watch?v=W7N4XnZQF78
## 設計模式分類
設計模式太多了
主要使用
* 單例 (singleton)
* 註冊表 (registry)
* 工廠 (factory)
* 觀察者 (observer)
* 依賴注入 (denpendency injection)
## 實際應用
你必須實際把設計模式應用在自己的作品中,經過大腦的慎密思考,當在維護自己的作品時,思考如何讓作品更棒時,設計模式就會不知不覺、悄悄地內化了。甚至不需要知道用的是什麼名字的設計模式,因為它已經是內在的一部分
## 設計模式 - 單例模式 (Singleton) (ps 在 laravel叫 trait)
https://ithelp.ithome.com.tw/articles/10203092
## 內容
單例模式
定義:**只有一個實例**,而且自行實例化並向整個系統提供這個實例。
屬於創建模式,
這個模式涉及到一個單一的類別,他必須要創建自己的實例,
並且確保只有單一個對象被創建。
這個類別提供一個方法訪問其被創建的唯一一個對象。
**存取IO和資料庫等資源,這時候要考慮使用單例模式。**
有幾種方式可以實現單例模式
* 懶散(Lazy)模式(線程不安全)
* 懶散模式(線程安全)
* 積極模式
* 雙重鎖 (Double ChockLock)
* 登記式(靜態內部類)
* 枚舉 (enumeration)
## 單例模式
## 理解区分:简单工厂模式,工厂方法模式,抽象工厂模式
https://zhuanlan.zhihu.com/p/343638837
## 策略模式 vs 工厂模式
工厂模式是一种创造模式。战略模式是一种运营模式。换句话说,工厂模式用于创建特定类型的对象。策略模式用于以特定方式执行一个操作(或一组操作)。在经典示例中,工厂可能会创建不同类型的动物:狗,猫,老虎,而策略模式将执行特定的动作,例如,移动;使用“跑步”,“步行”或“移动”策略。
## Strategy Pattern 策略模式(非常重要 常用)
情境: 同一個行為有數種方案可以選擇,使用者可以在執行期間再決定要用哪一個
秘訣:
* 出現用switch case來切換行為的場合
* 將行為定義成介面,實做出同一體系的類別
* 在方法參數中注入
注意這跟工廠差在 這是行為
工廠是new 不同
簡易工廠不一定有同樣方法
但抽象工廠才會有一樣方法
範例: 訂單希望提供數種物流選項以計算運費,但每家一種都要修改訂單類別的程式碼
```
class Order
{
public function calculateFee($shipmentName)
{
switch ($shipmentName) {
case 'Hsinchu': // 新竹貨運
$fee = .... ;
break;
case 'BlackCat': // 黑貓貨運
$fee = .... ;
break;
case 'PostOffice': // 郵局
$fee = .... ;
break;
default:
break;
}
}
}
```
https://github.com/3masterplus/book/blob/master/%E5%A4%A7%E8%AF%9D%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F(%E5%B8%A6%E7%9B%AE%E5%BD%95%E5%AE%8C%E6%95%B4%E7%89%88).pdf



一樣的抽成抽象父class
不同行為堆在同一個class就很容易用switch
但如果一個一個封裝就可以避免
策锐封裝變化
## 抽象工廠(Abstract Factory)
工厂都可以生产 button 和 border,那么把创建这两个产品的方法抽象出来,这个抽象出来的方法叫做抽象工厂类,两个工厂都要实现这个抽象类
有共同的方法類型,但實作方式不同,得出來的結果也可能不同
e.g.
棒球打者每個人都需要打擊(共同的方法類型)
但每個人的打擊姿勢都不同(實作方式不同)
每個打擊者可能擅長打出滾地球或是高飛球(得出來的結果也可能不同)
## ENV 模式
laravel
https://www.youtube.com/watch?v=wXwiztqJFdM&ab_channel=LaravelDaily
https://juejin.cn/post/6997230227868876830
## crobtab

還沒試過 必須多安裝一個ext
## 生成器(Builder)
類似的產品,有類似的複雜的建造流程
用interface去規劃藍圖

像這個 我只要drive
沒就去做出來執行
有的話就去執行
執行啥呢
按照規規劃走
pizza要配料 要考過 要給人
就按照流程那樣
## 工廠方法(Factory Method)
生產方式類似、少部分有些許的不同
以laravel來說每個view()這種就是
如果你建構她要很多預設 那他就很適合用工廠
不關心來源 只關係如何make
預設不只說是建構式喔 function也是

validate也是這樣

## 原型(Prototype)
產生新物件成本過高時,直接複製先前生成的原型物件
## 簡單工廠(Simple Factory)
https://kejyuntw.gitbooks.io/design-pattern-for-php/content/common-design-pattern/creational/common-design-pattern-creational-simple-factory.html
簡易工廠不一定有同樣方法
工廠是建立
動作不要用工廠
要用測瑞
把不同點封裝起來
主要是把決定new哪個做成一個class可以看上面OOP截圖
封裝這個class讓他來決定
並保有擴充跟單一原則
但抽象工廠才會有一樣方法
我們如果想要煮東西給自己吃,我們需要自己「準備食材」、「烹煮食材」、「上菜」
```
<?php
/**
* 抽象"烹煮"類別
*/
abstract class Cook {
// 準備食材
public abstract function prepareIngredient();
// 烹煮食材
public abstract function cooking();
// 上菜
public abstract function serve();
}
?>
```
假如我們想要吃咖哩,我們會這樣做:
```
<?php
/**
* 咖哩
*/
class Curry extends Cook
{
// 準備食材
public function prepareIngredient()
{
echo "準備「馬鈴薯」、「蘿蔔」、「洋蔥」、「肉」\n";
}
// 烹煮食材
public function cooking()
{
echo "下鍋炒肉,等肉熟之後,將「馬鈴薯」、「蘿蔔」、「洋蔥」加到鍋裡並加滿水,等水滾加入咖哩塊悶熟即可\n";
}
// 上菜
public function serve()
{
echo "盤子放上白飯,將咖哩淋在白飯周圍即可\n";
}
}
$curry = new Curry;
$curry->prepareIngredient(); // 準備食材
$curry->cooking(); // 烹煮食材
$curry->serve(); // 上菜
?>
```
很好用
都用在同一個東西 不同type那種感覺
例如上次寫的 Excel 不同的excel 但都是excel
例如
計算機crud的也是
加減乘除都是計算
可以用工廠去做
因為這樣可擴充
之後可能還會增加
開根號之類的
## 工廠策列結合

同一個父類別
然後type區分
這樣好處是
不同點封裝
一樣點一樣去跑
## Command Pattern 命令模式
https://www.youtube.com/watch?v=GQzfF5EMD7o
像是加減乘除
你可以拆成四個
然後組合
重點可以 當前的 - add 的 或 當前的 +當前的
感覺就是單一封閉的進階
單一是可以擴充
這是單一可以反向
所以我覺得就是拆細閱好就對了拉
舉例
save
exit
save and exit
前面兩個命令
後面就能使用他們兩個
減少重複
感覺跟公司用的依樣
這樣會比較累
但之後會比較輕鬆
## Facade Pattern
https://www.youtube.com/watch?v=fHPa5xzbpaA
fetch替換成axios
這模式是為了方便替換 有點OOP的五大原則中的替換原則
## Singleton Pattern

單例模式很適合在測試時候使用
單例模式基本上是一個美化的全局變量
## Builder Pattern
很像公司那樣
定義好抽象
上層就只要選要得去建立
## povider pattern
就像pizza連鎖店一樣
他負責pizza所有的東西
包含經理人員 如何去做之類的
基本上會像package一樣
負責所有的東西
###### tags: `觀念重點區`