goF23設(shè)計模式~思想學(xué)習(xí)筆記(二)
goF23設(shè)計模式~思想學(xué)習(xí)筆記(三)
設(shè)計模式-終身學(xué)習(xí)
前言
你是否早已領(lǐng)會到,時間少、開發(fā)任務(wù)重,草草了事完成功能開發(fā),原型變動版本迭代,相當(dāng)于推翻重來,一個類的變動導(dǎo)致很多地方都得跟著調(diào)整,一不小心漏了一種情況,測試難覆蓋,導(dǎo)致悲劇產(chǎn)生呢。那是因為你在開發(fā)中針對問題沒有使用更優(yōu)雅的方案解決--設(shè)計模式,不是老生常談,而是每次都是新收獲,經(jīng)典就是這樣不會過時,希望你帶著空杯的心態(tài)慢慢領(lǐng)悟,主要是思想的提升,為什么這么寫優(yōu)雅(有時代碼量反而多了);把變和不變的東西搞清楚,哪些需要抽象。設(shè)計模式是很必要我們投入時間和精力學(xué)習(xí)的,一段時間后再看就會不一樣了。
本筆記是觀看該視頻的筆記和感悟,邏輯一致代碼跟隨演練,部分代碼簡化處理包含UML類,設(shè)計模式是前輩門在軟件工程總結(jié)的經(jīng)驗和是解決問題的方案,貴在思想領(lǐng)悟,實際的開發(fā)框架中使用的可能是此教程設(shè)計模式的變種,但萬變不離其宗,本筆記記錄的是標(biāo)準(zhǔn)寫法。想要學(xué)好設(shè)計模式需要先弄清其原理,多思考總結(jié),才能更好吸收。如有不對的地方請賜教,我們一起學(xué)習(xí)成長。
你可能會問既然有視頻了為啥還有會這個筆記呢,我去看視頻好了,筆記是我的學(xué)習(xí)總結(jié)(寫給自己和需要的人),視頻時間很有點長,我筆記會記錄核心邏輯,不清晰的可以看視頻,或者以后,用來查閱。同樣我也非常贊成你和我一樣學(xué)完后,整理出學(xué)習(xí)筆記。筆記不僅僅是寫給他人更是寫給自己的(《高效學(xué)習(xí)》-教就是最好的學(xué))。
GoF23設(shè)計模式
B站視頻鏈接
全套代碼地址 https://gitee.com/zhuyunjiandull/design_pattern
設(shè)計模式的六大原則
| 原則 | 解釋 |
|---|---|
| 單一原則 (SRP | 一個類只做一件事 |
| 開放-封閉原則(OCP | 軟件實體(類、模塊、函數(shù))可以拓展,但是不可修改 |
| 依賴倒轉(zhuǎn)原則(DIP) | A.高層模塊不應(yīng)該依賴底層,兩個都應(yīng)該依賴抽。B.抽象不應(yīng)該依賴細(xì)節(jié),細(xì)節(jié)依賴抽象 |
| 里氏代換原則(LSP) | 子類型必須能夠替換掉它們的父類型 |
| 迪米特法則(LoD) | 如果兩個類不必直接通信,那么這兩個類不應(yīng)當(dāng)發(fā)生直接的相互作用。如果其中一個類需要調(diào)用另一個類的某一個方法的話,可通過第三者發(fā)起這個調(diào)用 |
| 合成/聚合復(fù)用原則(CARP) | 盡量使用合成/聚合,盡量不要使用類繼承 |
分類和特性
經(jīng)典設(shè)計模式大方向分為三大類,創(chuàng)建型模式、結(jié)構(gòu)型模式、行為型模式。創(chuàng)建型模式里面包含5個,結(jié)構(gòu)型模式包含7個,行為型模式包含11個。
創(chuàng)建型模式:主要用于處理對象的創(chuàng)建,實例化對象。但是,這可能會限制在系統(tǒng)內(nèi)創(chuàng)建對象的類型或數(shù)目。
結(jié)構(gòu)型模式:處理類或?qū)ο箝g的組合。它將以不同的方式影響著程序,允許在補充寫代碼或自定義代碼的情況下創(chuàng)建系統(tǒng),而且具有重復(fù)使用性和應(yīng)用性能。
行為型模式:描述類或?qū)ο笤鯓舆M(jìn)行交互和職責(zé)分配。影響系統(tǒng)的狀態(tài)、行為流,簡化、優(yōu)化并且提高應(yīng)用程序的可維護(hù)性。
創(chuàng)建型模式
- 單例模式
- 工廠方法模式
- 抽象工廠模式
- 建造者模式
- 原型模式
結(jié)構(gòu)型模式
- 適配器模式
- 裝飾器模式
- 代理模式
- 外觀模式
- 橋接模式
- 組合模式
- 享元模式
行為型模式
- 模板方法模式
- 觀察者模式
- 迭代子模式
- 責(zé)任鏈模式
- 命令模式
- 備忘錄模式
- 狀態(tài)模式
- 訪問者模式
- 中介者模式
- 解釋器模式
- 策略模式
如何合理的選擇該用什么樣的設(shè)計模式?
創(chuàng)建型模式
單例模式(Singleton Pattern): 保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
工廠方法模式(Factory Method Pattern): 定義一個用于創(chuàng)建對象的接口,讓子類決定將哪一個類實例化。Factory Method使一個類的實例化延伸到其子類。
抽象工廠模式(Abstract Factory Pattern): 提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們具體的類。
建造者模式(Builder Pattern): 將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
原型模式(Prototype Pattern): 用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這個原型來創(chuàng)建新的對象。
結(jié)構(gòu)型模式
適配器模式(Adapter Pattern): 將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
裝飾模式(Decorator Pattern): 動態(tài)地給一個對象添加一些額外的職責(zé)。就擴展功能而言,它比生成子類方式更為靈活。
代理模式(Proxy Pattern): 為其他對象提供一個代理以控制對這個對象的訪問。
外觀模式(Facade Pattern): 為子系統(tǒng)中的一組接口提供一個一致的界面,F(xiàn)acade模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用。
橋接模式(Bridge Pattern): 將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。
組合模式(Composite Pattern): 將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。它使得客戶對單個對象和復(fù)合對象的使用具有一致性。
享元模式(Flyweight Pattern): 運用共享技術(shù)有效地支持大量細(xì)粒度的對象。
行為型模式
模板方法模式(Template Method Pattern): 定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
責(zé)任鏈模式(Chain of Responsibility Pattern): 為解除請求的發(fā)送者和接收者之間耦合,而使多個對象都有機會處理這個請求。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它。
解釋器模式(Interpreter Pattern): 給定一個語言,定義它的文法的一種表示,并定義一個解釋器, 該解釋器使用該表示來解釋語言中的句子。
觀察者模式(Observer Pattern): 定義對象間的一種一對多的依賴關(guān)系,以便當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并自動刷新。
迭代器模式(Iterator Pattern): 提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內(nèi)部表示。
命令模式(Command Pattern): 將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進(jìn)行參數(shù)化;對請求排隊或記錄請求日志,以及支持可取消的操作。
備忘錄模式(Memento Pattern): 在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復(fù)到保存的狀態(tài)。
狀態(tài)模式(State Pattern): 允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為。對象看起來似乎修改了它所屬的類。
訪問者模式(Visitor Pattern): 表示一個作用于某對象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
中介者模式(Mediator Pattern): 用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
策略模式(Strategy Pattern): 定義一系列的算法,把它們一個個封裝起來,并且使它們可相互替換。本模式使得算法的變化可獨立于使用它的客戶。
類圖關(guān)系箭頭和線說明


核心思想分析領(lǐng)悟
創(chuàng)建型模式
1. 單例模式
//1.餓漢式:靜態(tài)常量 特點:類裝載創(chuàng)建,可能會浪費內(nèi)存
class SingletonHungry {
//1.私有化構(gòu)造
private SingletonHungry(){}
//2.類內(nèi)部創(chuàng)建對象
private final static SingletonHungry instance = new SingletonHungry();
//3.對外提供獲取實例方法
public static SingletonHungry getInstance() {
return instance;
}
}
//2.懶漢式線程不安全,
class SingletonLazy {
//1.私有化構(gòu)造
private SingletonLazy(){}
//2.類內(nèi)部創(chuàng)建對象
private static SingletonLazy instance;
//3.對外提供獲取實例方法
public static SingletonLazy getInstance() {
if(instance==null){
instance = new SingletonLazy();
}
return instance;
}
}
//2.2懶漢式 特點:線程安全同步寫法,效率低,
class SingletonLazy2 {
//1.私有化構(gòu)造
private SingletonLazy2(){}
//2.類內(nèi)部創(chuàng)建對象
private static SingletonLazy2 instance;
//3.對外提供獲取實例方法
public static synchronized SingletonLazy2 getInstance() {
if(instance==null){
instance = new SingletonLazy2();
}
return instance;
}
}
//3 雙重檢測
class SingletonDoubleCheck {
//1.私有化構(gòu)造
private SingletonDoubleCheck() {}
//2.類內(nèi)部創(chuàng)建對象
private static volatile SingletonDoubleCheck instance;
//3.對外提供獲取實例方法
public static SingletonDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingletonDoubleCheck.class) {
if (instance == null) {
instance = new SingletonDoubleCheck();
}
}
}
return instance;
}
}
//4.靜態(tài)內(nèi)部類
class SingletonStaticClass {
//1.私有化構(gòu)造
private SingletonStaticClass() {}
//2.內(nèi)部類
private static class SingletonInstance {
private static final SingletonStaticClass INSTANCE = new SingletonStaticClass();
}
//3.對外提供獲取實例方法
public static SingletonStaticClass getInstance() {
return SingletonInstance.INSTANCE;
}
}
//5.枚舉
enum SingleEnum {
INSTANCE;
public void method(){
}
}
public class SingletonTest {
public static void main(String[] args) {
// SingletonHungry creation.singleton = SingletonHungry.getInstance();
// System.out.println(creation.singleton);
// SingletonHungry singleton2 = SingletonHungry.getInstance();
// System.out.println(singleton2);
// System.out.println(creation.singleton==singleton2);
System.out.println(SingletonDoubleCheck.getInstance());
System.out.println(SingleEnum.INSTANCE);
}
}
2. 工廠模式 : 通過外部參數(shù)直接獲取想要的對象實例,實例初始化步驟放到 OrderPizza 內(nèi)部
2.1 不使用設(shè)計模式

public class OrderPizza {
Pizza getPizza(String name){
Pizza pizza = null;
switch (name){
case "chess":
pizza = new ChessPizza();
break;
case "greek":
pizza = new GreekPizza();
break;
}
if(pizza != null){
pizza.prepare();
pizza.baker();
pizza.cut();
pizza.box();
}
return pizza;
}
}
缺點:無工廠增加一個種類 需要需改 OrderPizza不符合開閉原則
2.2 簡單工廠 改進(jìn)方案

//工廠類 增加種類只需要修改工廠類SimpleFactory 業(yè)務(wù)類OrderPizza不需要修改
public class SimpleFactory {
static Pizza getPizza(String name){
Pizza pizza = null;
switch (name){
case "chess":
pizza = new ChessPizza();
break;
case "greek":
pizza = new GreekPizza();
break;
}
return pizza;
}
}
//業(yè)務(wù)
public class OrderPizza {
Pizza orderPizza(String name){
Pizza pizza = SimpleFactory.getPizza(name);
if(pizza != null){
pizza.prepare();
pizza.baker();
pizza.cut();
pizza.box();
}
return pizza;
}
}
2.3 工廠方法 : 定義一個用于創(chuàng)建對象的接口,讓子類決定將哪一個類實例化。Factory Method使一個類的實例化延伸到其子類。

enum OrderType {
bJType,
lDType
}
class OrderPizza {
Pizza createPizza(OrderType orderType,String name){
Pizza pizza = null;
if(orderType==OrderType.bJType){
pizza = new BJOrderPizza().orderPizza(name);
}else if(orderType==OrderType.lDType) {
pizza = new LDOrderPizza().orderPizza(name);
}
if(pizza != null){
pizza.prepare();
pizza.baker();
pizza.cut();
pizza.box();
}
return pizza;
}
}
class BJOrderPizza {
Pizza orderPizza(String name){
Pizza pizza = null;
switch (name){
case "chess":
pizza = new BJChessPizza();
break;
case "greek":
pizza = new BJGreekPizza();
break;
}
return pizza;
}
}
class LDOrderPizza {
Pizza orderPizza(String name){
Pizza pizza = null;
switch (name){
case "chess":
pizza = new LDChessPizza();
break;
case "greek":
pizza = new LDGreekPizza();
break;
}
return pizza;
}
}
3. 抽象工廠 :提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們具體的類。

public class OrderPizza extends Object{
Pizza orderPizza(AbFactory factory, String name){
Pizza pizza = factory.createPizza(name);
if(pizza != null){
pizza.prepare();
pizza.baker();
pizza.cut();
pizza.box();
}
return pizza;
}
}
public class Test {
public static void main(String[] args) {
//抽象工廠方法
OrderPizza orderPizza = new OrderPizza();
orderPizza.orderPizza(new BJFactory(),"chess");
orderPizza.orderPizza(new BJFactory(),"greek");
orderPizza.orderPizza(new LDFactory(),"chess");
orderPizza.orderPizza(new LDFactory(),"greek");
}
}
4. 建造者: 將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。

public class HouseDirector {
private HouseBuilder builder;
public HouseDirector(HouseBuilder builder) {
this.builder = builder;
}
//指揮 建造流程
House buildHouse(){
builder.buildBasic();
builder.buildWall();
builder.buildRoof();
return builder.getHouse();
}
}
abstract public class HouseBuilder {
//創(chuàng)建產(chǎn)品
protected House house = new House();
//創(chuàng)建行為定義
public abstract void buildBasic();
public abstract void buildWall();
public abstract void buildRoof();
public House getHouse() {
return house;
}
}
public class ComHouse extends HouseBuilder {
private String name = "ComHouse ";
@Override
public void buildBasic() {
String s = name + "打地基";
house.setBasic(s);
System.out.println(s);
}
@Override
public void buildWall() {
String s = name + "砌墻";
house.setWall(s);
System.out.println(s);
}
@Override
public void buildRoof() {
String s = name + "蓋屋頂";
house.setRoof(s);
System.out.println(s);
}
}
5. 原型模式:用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這個原型來創(chuàng)建新的對象。
public class Video implements Cloneable,Serializable{
private String name;
private Date data;
public Video(String name, Date data) {
this.name = name;
this.data = data;
}
@Override
protected Object clone() throws CloneNotSupportedException {
var obj = (Video) super.clone();
obj.data = (Date) data.clone();
return obj;
}
protected Object deepClone() {
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
Object obj = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
obj = ois.readObject();
}catch (Exception e){
System.out.println(e);
}finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
}catch (Exception e){
System.out.println(e);
}
}
return obj;
}
public void setData(Date data) {
this.data = data;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Video{" +
"name='" + name + '\'' +
", data=" + data +
'}';
}
}