發表文章

目前顯示的是 2月, 2020的文章

設計模式 - 索引

前言 此篇文章是Design Pattern的導覽頁面 項目 雜談 三本書搞定Design Pattern Creational Patterns 設計模式 - 建構者模式 (Creational Patterns - Build Pattern) 設計模式 - 工廠模式 (Creational Patterns - Factory Pattern) 設計模式 - 單例模式 (Creational Patterns - Singleton Pattern) 設計模式 - 原型模式 (Creational Patterns - Prototype Pattern) Structural Ptterns 設計模式 - 適配器模式 (Structural Patterns- Adapter Pattern) 設計模式 - 橋接模式 (Structural Patterns - Bridge Pattern) 設計模式 - 組合模式 (Structural Patterns - Composite Design Pattern) 設計模式 - 裝飾者模式 (Structural Patterns - Decorator Design Pattern) 設計模式 - 包裝模式 (Structural Patterns - Facade Design Pattern) 設計模式 - 享元模式 (Structural Patterns - Flyweight Design Pattern) 設計模式 - 代理人模式 (Structural Patterns - Proxy Design Pattern) Behavioral Patterns 設計模式 - 策略模式 (Behavioral Patterns - Strategy Design Pattern) 設計模式 - 狀態模式 (Behavioral Patterns - State Design Pattern) 設計模式 - 模板方法模式 (Behavioral Patterns - Template Method Design Pattern) 設計模式 - 責任鍊模式 (Behavioral Patterns - Chain of Responsibil

三本書搞定Design Pattern

圖片
前言 這篇文章推薦我在自學Design Pattern時閱讀的書籍,以及分享我學習的歷程(當然還在持續增進中)。 先來聊聊自己接觸Design Pattern的心路歷程 在我碩一的時候開始閱讀Design Pattern,完全是霧裡看花,只是記住Pattern的名稱。而開始工作第一年,在讀一次對於一些基本封裝的Pattern開始有點感覺,但實際要用到專案上還是有點距離,到目前工作三年了,自己也開始主導一些專案後,再回來複習一次,發現許多Pattern我早就默默地在使用了,而且對於每個Pattern都有許多的感觸與自己的想法。 總歸這些年來對於Design Pattern的心得,我覺得Design Pattern他並不是一個要去學的東西,它更像是一個經驗的總和與梳理,當自己做過的專案不多時道聽塗說的使用,其實這樣一輩子都不會知道自己為什麼要使用Design Pattern,但是在自己實踐過的專案變多後,看過太多失控的程式碼,看過太多修改的坑坑洞洞,就會知道每個Design Pattern它的核心價值以及未來使用的方向。 廢話不多說,下面馬上介紹我個人在學習Design Pattern時閱讀的書籍。 深入淺出-設計模式 深入淺出不必多說,是每個初學者都需要看的書,不管甚麼系列。深入淺出-設計模式這本書可以讓初學者透過書上的實作慢慢地去理解,去想像Pattern的使用,它是以漸進式的方法讓讀者知道每個Pattern使用時機。 博客來訂購連結 設計模式的解析與活用 設計模式的解析與活用,與深入淺出比較大的差異在於,深入淺出用比較多讓讀者會感興趣的方式教學甚麼是設計模式,所以適合初學者。而這本設計模式的解析與活用它會強調使用的時機,並且深入的解析Pattern的使用時機,還有帶領開發者們從Code的層面變成從Pattern的層面去設計。 博客來訂購連結 揭開設計模式的秘辛:設計模式 第1¾版 揭開設計模式的秘辛:設計模式 第1¾版,是我推薦的最後一本書,也是我認為看完上述兩本後在開始閱讀的書。這本書更多在於思考的昇華,還有介紹兩個不再23個模式中的Design Pattern,在第二章節還有一個較大型的設計範例,讓讀者不會只圍繞一個Design Pattern學習,而是用全部的Design Pattern去思考。 博客來訂購連結 結論 用

設計模式 - 命令設計模式 (Behavioral Patterns - Command Pattern)

圖片
前言 對我個人而言,其實我私心認為Command Pattern與Chain of Responsibility是非常相似的。 Chain of Responsibility意旨將邏輯拆開,透過物件之間的連接做呼叫,物件間的聯就透過建構者或Dependency Inject注入。 而其中的差別在於,粒度的不同,Commande Pattern比較偏向將一個物件原本的method拆解成一個個的Command,而Chain of Responsibility的Handler粒度更大一點,更像是一個個完整邏輯的物件。 類別圖 設計Command介面 實作Command介面並解複寫Execute方法 透過Receiver組裝Command組織成自己的物件邏輯,提供給Client呼叫 範例 英雄遊戲中的,常用組合招式非常適合用Command Pattern實踐,邏輯如下 使用者可以將不同招式組裝成快捷鍵施放 範例: 施毒 -> 祝福(加攻擊力) -> 攻擊 實作過程 設計SkillCommand 設計不同的Skill實作SkillComand並複寫Method實踐自己的邏輯 透過一個Reciver組裝每個Skill包裝成自己的邏輯 Client執行 import java.util.LinkedList; import java.util.Queue; interface SkillCommand { void execute(); } class Poison implements SkillCommand { @Override public void execute() { System.out.println("Poison your enemy"); } } class Bless implements SkillCommand { @Override public void execute() { System.out.println("Bless yourself"); } } class Attack implements SkillCommand {

設計模式 - 觀察者模式 (Behavioral Patterns - Observer Pattern)

圖片
前言 觀察者(Observer Pattern) 定義 創造一對多的連結(Subject-Observer),當被綁定的物件狀態變動的話,則通知其他物件 可以保護物件不做內部破壞去通知其他物件執行功能,可以透過觀察者封裝此物件執行通知 我們只要設想,觀察者就是一個廣播機制,Subject是負責廣播的而和他同個頻道(Observer)都可以接收到他的廣播,在Observer Pattern使用物件導向(多形、封裝)的方法去實踐他 類別圖 創建Subject介面負責和Observer關聯 Observer主要透過Subject的觸發,接收更動的訊息 範例 英雄遊戲中適合使用Observer Pattern(觀察者模式),非遊戲地圖莫屬。我們現在的遊戲業務內容是,每一張地圖都需要排隊,玩家可以訂閱此地圖(若是當地圖開放的時候(沒人在裡面)就會通知玩家) 設計MapSubject負責發送通知的內容 將地圖繼承MapSubject擴充發送通知的方法 設計UserObserver負責接收通知內容 將User繼承UserObserver擴充收通知的方法 import java.util.ArrayList; import java.util.List; abstract class MapSubject { private String mapId; public MapSubject(String mapId) { this.mapId = mapId; } private List<MapObserver> observers = new ArrayList<>(); public void addObserver(MapObserver mapObserver) { observers.add(mapObserver); } public void notifyChange() { for (MapObserver mapObserver : observers) { mapObserver.update(mapId); } }; } class

設計模式 - 責任鍊模式 (Behavioral Patterns - Chain of Responsibility Pattern)

圖片
前言 我們先從Chain of Responsibility字面定義來看這個設計模式,他有責任還有鍊,那代表可能他會將不同的演算法串起來,所以這個模式我們可以猜測這個模式的設計會圍繞 如何讓每個演算法串起來 如何串 串起來的優點 而果不其然,責任鍊模式的定義如下 避免耦合,將每個呼叫的要求透過鍊的概念傳遞 每個邏輯流程會由多個handler串起 會透過recrsive的方式詢問全部的handler 類別圖 定義出Handler要被外部(其他handler)呼叫的介面 而Handler聚合的方法會有點類似LinkedList,對綁定在自己下方的Handler呼叫 範例 我們來想一下英雄遊戲可以使用責任鍊模式,我想武器鍛造應該很適合 武器鍛造流程 打鐵 (機率提升攻擊) 鑲寶石 (機率提升特殊效果) 加把手 (機率提升命中) 取出 (出貨) 所以我們會有四個handler,依照順序包裝我們的handler,執行 abstract class Handler { Handler nextHandler = null; public Handler(Handler nextHandler) { this.nextHandler = nextHandler; } public void execute() { action(); if (nextHandler != null) { nextHandler.execute(); } } abstract void action(); } class ImproveAttackHandler extends Handler { public ImproveAttackHandler(Handler nextHandler) { super(nextHandler); } @Override void action() { System.out.println("Improve attack ability"); } } class

設計模式 - 模板方法模式 (Behavioral Patterns - Template Method Design Pattern)

圖片
前言 Template Pattern就像是之前談過的Builder Pattern和Strategy Pattern混合版本,這個Pattern主要在 定義一個演算法流程介面,讓不同的實作圍繞著介面的方法去繁衍出不同的演算法 而這些流程都稱為一個佔位(佔住一個流程的位子),為何稱為佔位,我們舉個例子,今天如果我們要做英雄攻擊動畫,而這個程式設計我們可以很簡單的就叫做Attack,但是問題來了 不同的英雄攻擊動作不一樣 ,所以我們必須將這個攻擊拆分成不同的細節(攻擊方法包含-舉手、前進、揮砍、收起武器),而這些動作就可以稱為placeholders(我自稱佔位QQ),讓整個演算法的粒度變小,可以透過class繼承的方式去修改這些粒度 和Strategy與Builder相比 和Strategy相比,策略模式的意象聚焦於不同演算法的切換(沒有佔位切分粒度的概念)-我個人私心認為如果策略模式要變得更複雜的話也是一種Template模式 和Builder相比Builder也是讓Client分不同步驟去呼叫Object,但是他的目的是創建一個物件,而Template Method更聚焦於執行一個流程 類別圖 實踐方法 定義出你的演算法方法介面 (攻擊演算法-舉手、揮砍、收刀) 根據不同的實作具演化你的每個演算法佔位(placeholder或細節)流程 範例 定義出英雄攻擊的Template Method介面 (不一定是interface,在此用default作為共用方法) 不同類型的攻擊繼承此模板方法 interface AttackMethod { default void attack() { pickUpWeapon(); moveForward(); hitEnemy(); putDownWeapon(); }; void pickUpWeapon(); void moveForward(); void hitEnemy(); void putDownWeapon(); } class MagicianAttack implements AttackMethod { @Override pu

設計模式 - 狀態模式 (Behavioral Patterns - State Design Pattern)

圖片
前言 在介紹狀態模式前,必須先講解一下狀態模式與策略模式的關係。 先看兩張圖 策略模式 狀態模式 我們可以看到兩張類別圖可以說是一模一樣,但是差別在哪呢? 策略模式 可以讓呼叫端轉換不同的演算法 他算是主動的使用我們的function並且抽換 狀態模式 給物件不同的狀態,並且限制他只能在這狀態做哪些事情 他算是被動的被控制只能使用那些function 舉例 策略模式 以策略模式文章中的技能,技能Service可以控管要呼叫哪個Skill物件使用,去使用就適合策略模式 狀態模式 角色今天可能會有禁咒、石化,那我們需要先把角色可以做的事情抽出來(攻擊、移動、技能)創出一個行為介面,再依不同的狀態實做這個介面,而這些物件則可以在實作中根據狀態,限制這些行為。 範例 英雄今天可能會被施加石化、禁咒,那我們看一下狀態模式如何讓我們的程式碼,抽象話 讓正常、石化、禁咒狀態實作State介面 英雄呼叫State介面的方法(可抽換不同的狀態實作) 再由Context(設定不同的狀態) interface HeroState { void run(); void useSkill(); void attack(); } class PetrochemicalState implements HeroState { @Override public void run() { System.out.println("Your are a stone so you can't do anything"); } @Override public void useSkill() { System.out.println("Your are a stone so you can't do anything"); } @Override public void attack() { System.out.println("Your are a stone so you can't do anything")

設計模式 - 策略模式 (Behavioral Patterns - Strategy Design Pattern)

圖片
前言 策略模式,主要是讓相似的行為一起時做一個介面,並且可以抽換他們。在沒使用策略模式前,我們可能會用大量的if/else or swithc去撰寫我們的邏輯,而透過策略模式可以將每個邏輯包裝好,並且透過介面方法執行。 類別圖 將我們要執行的演算法繼承一個策略的介面 客戶端統一呼叫此策略介面的方法 這代表著我隨時可以抽換不同的演算法 範例 英雄遊戲的技能施放,技能施放不管是怎樣的效果,他都是一個技能,非常適合用策略模式來撰寫。 我們火焰攻擊和治癒都是實作Skill介面 在SkillService中,再透過Map和String的比對拿出Skill實做並且使用 import java.util.HashMap; import java.util.Map; interface Skill { void doAction(); } class FireSkill implements Skill { @Override public void doAction() { System.out.println("Use fire to attack"); } } class HealSkill implements Skill { @Override public void doAction() { System.out.println("Heal myself"); } } class SkillService { private Map<String, Skill> skillMap = new HashMap<>(); public SkillService() { skillMap.put("FireAttack", new FireSkill()); skillMap.put("Heal", new HealSkill()); } public void doAction(String skillType) { Skill skill = skillMap.g

設計模式 - 代理人模式 (Structural Patterns - Proxy Design Pattern)

圖片
設計模式 - 代理人模式 (Structural Patterns - Proxy Design Pattern) 前言 在開始前我們先想想代理人這個詞彙,在中文我們用到代理人時通常都在甚麼時機呢? 當將軍要出席敵國晚宴時,可能會找個長的和他很像的人當作代理人 如果是鴻門宴的話,將軍還是安全的 當老闆出國度假時,他可能需要一個職務代理人 可以幫他篩選那些事情需要打給他 所以代理人通常代表著 保護本體 可以做決定的篩選 而Desing Pattern的Proxy也是相似概念 保護本體物件 (決定誰可以Accesdd/接觸到此物件) 在Access到本體時,會有一層篩選 類別圖 對需要做Proxy的物件切分出介面和實作 將Proxy一同實作此介面 (讓Proxy和被代理的物件可以做到互換) 客戶端在呼叫時呼叫此Proxy介面 範例 以英雄遊戲中的玩家加入聯盟為範例,我們可以透過Proxy讓我們的聯盟物件包持單一原則,只做加入跟退出,而目前的其他檢驗就由Proxy做掉。 import java.util.HashSet; import java.util.Set; interface Team { boolean join(String name); boolean quit(String name); } class League implements Team { private Set<String> heroSet = new HashSet<>(); @Override public boolean join(String name) { return heroSet.add(name); } @Override public boolean quit(String name) { return heroSet.remove(name); } public boolean isExist(String name) { return heroSet.contains(name); } } class LeagueProxy im

設計模式 - 享元模式 (Structural Patterns - Flyweight Design Pattern)

圖片
前言 甚麼是Flyweight Pattern? 幫助你節省記憶體開銷 透過共享物件的方式 最常見的例子 String : 每次新增一個String的時候,都會將String丟進String pool,再讓物件指向這個String memory。 String str1 = "test"; String str2 = "test"; System.out.println(str1 == str2) // true 實踐方式 撰寫Flyweight介面與物件 撰寫Flyweight工廠(主要節省記憶體邏輯在此),負責管理和創建Flyweight 類別圖 範例 我們可以思考一下,在英雄遊戲中有那些東西可以使用享元模式。 重複製造 同物件的性質一樣 我想武器添加物系統可以使用享元模式,因為武器中插的寶石不管插在哪種類的武器裡,他們的功效都是一樣的,而如果為每把武器都創建新的寶石物件,那太消耗記憶體了。 程式行為 為武器加上寶石 若是已經存在的寶石則不在new 物件 透過DiamondFactory去控制要不要new新物件的邏輯 import java.util.ArrayList; import java.util.HashMap; import java.util.Map; abstract class Weapon { ArrayList<Diamond> diamonds = new ArrayList<>(); public void addDiamond(Diamond diamond) { diamonds.add(diamond); } abstract void attack(); } class Sword extends Weapon { @Override void attack() { System.out.println("Sword attack"); diamonds.forEach((x) -> { System.out.println("Use "

設計模式 - 包裝模式 (Structural Patterns - Facade Design Pattern)

圖片
前言 Wiki對於 Decorator Pattern的定義如下: The Facade [1] design pattern is one of the twenty-three well-known GoF design patterns that describe how to solve recurring design problems to design flexible and reusable object-oriented software, that is, objects that are easier to implement, change, test, and reuse. Facade Pattern應該是最常出現的Pattern之一,只要有基本物件觀念,基本上寫的許多Class都是Facade 將子物件包裝進主物件,簡化呼叫流程 讓呼叫端呼叫主物件 類別圖 範例 回到我們英雄遊戲活動,要與其他遊戲的英雄做聯名,這代表著我們需要呼叫許多外部系統,我們可以透過Facade Pattern將這些繁瑣的外部介面(or Api),包裝成我們統一的主介面 透過Facade包裝不同子系統的介面 class GameA { public String getHero(String heroName) { return "Game A hero"; } } class GameB { public String getHero(String heroName) { return "Game B hero"; } } class GameFacade { public String getHero(String heroName, String gameType) { if (gameType.equals("A")) { return new GameA().getHero(heroName); } else { return new GameB().getHero(heroName); }

設計模式 - 裝飾者模式 (Structural Patterns - Decorator Design Pattern)

圖片
前言 Wiki對於 Decorator Pattern的定義如下: The Decorator [3] design pattern is one of the twenty-three well-known GoF design patterns that describe how to solve recurring design problems to design flexible and reusable object-oriented software, that is, objects that are easier to implement, change, test, and reuse. Decorator模式最主要有兩點 圍繞著一個核心,創建hierarchy(階層體系) 讓核心被包裝在它的子物件中,增加功能 類別圖 根據要增加功能的核心,創建Decorator 讓核心可以被Decorator hierarchy的物件包裝 範例 英雄升階層範例,現在老闆要開放一個新功能,讓英雄可以根據等級升階。 英雄 -> 戰士 -> 騎士 / 聖騎士 而我們就以上面的升階當作Decorator的範例 說明: 英雄介面宣告攻擊行為 創建基本戰士Class 創建進階戰士Decorator 騎士和十字軍繼承Decorator並且延伸攻擊方法 interface Hero { void attack(); } class Warrior implements Hero { @Override public void attack() { System.out.println("Warrior attck"); } } abstract class IntermediateWarriorDecorator implements Hero{ private Hero warrior; public IntermediateWarriorDecorator(Hero warrior) { this.warrior = warrior; } public void originalA

設計模式 - 組合模式 (Structural Patterns - Composite Design Pattern)

圖片
前言 Wiki對於 Composite Pattern的定義如下: The Composite [2] design pattern is one of the twenty-three well-known GoF design patterns that describe how to solve recurring design problems to design flexible and reusable object-oriented software, that is, objects that are easier to implement, change, test, and reuse. 定議提到的組合模式引入可以帶來,更方便的實作、改變、測試和重用,而這些好處在介紹完範例後,再逐步分析。 類別圖 組合模式基本概念 將組合模式中的每個物件都定義成 “is a” 每個物件都會記成Component抽象類別 基本物件會被定義成Leaf Composite包裝Leaf,當作一個Leaf的集合 Composite會逐步的訪問每個包裝在內的子物件 範例 英雄遊戲,今天我們角色發展差不多了,需要開始讓玩家有更多的互動,所以老闆想到了戰團系統,而每個戰團都是由小隊組成(因為工城戰這樣比較好指揮)。看來這個新的系統設計非常適合我們剛剛學到的Composite Pattern,戰團(Composite)而小隊(Component),那我們開始撰寫吧。 創立群組(Group)概念,因為聯盟和小隊都是一個群組 將小隊包裝進聯盟裡 當要使用聯盟時,小隊就會逐步的被使用到 import java.util.ArrayList; abstract class Group { private String name; Group(String name) { this.name = name; } String getName() { return name; } public abstract void print(); public abstract void addGroup(Group group); } class Team

設計模式 - 橋接模式 (Structural Patterns - Bridge Pattern)

圖片
前言 GoF Design Pattern對於Bridge Pattern的定義如下: decouple an abstraction from its implementation so that the two can vary independently", introduced by the Gang of Four 橋接模式最主要就是將你的抽象與實作分離,達到極致的解偶獨立。 Class Diagram Abstraction: 將原本的主體抽換到只剩下虛擬的概念,例如(人類:只是吃喝拉撒睡的主體、遙控器:只是開機關機調整的主體) RefineAbstraction: 根據不同的需求實作主體 Implementator: 將原本主體的實際功能抽離,成為這個的Hierarchy(繼承結構),例如(人類:人類的吃和拉撒睡拉出在此結構實作) ConcreteImplementator: 根據不同的需求開發真實的行為 範例 此範例將英雄和英雄的行為抽離,並透過Bridge Pattern實踐 HeroAction: Implementator FireHeroAction: ConcreteImplementator IceHeroAction: ConcreteImplementator Hero: Abstraction Magician: RefineAbstraction Warrior: RefineAbstraction interface HeroAction { void kick(); void slash(); void beat(); } class FireHeroAction implements HeroAction { @Override public void kick() { System.out.println("Fire kick"); } @Override public void slash() { System.out.println("Fire slash"); } @Override

設計模式 - 適配器模式 (Structural Patterns- Adapter Pattern)

圖片
前言 適配器模式的使用時機,假想我們今天從台灣要去歐洲旅遊,可是平常常用的充電器根本不能用了(瓦數不同),那該怎麼辦呢? 轉接頭 講白了適配器模式(Adapter)就是一個轉接頭,為什麼程式碼需要用到轉接頭呢?當今天我們系統需要跟十年前開發的系統做連結時,因為此系統已經完全沒人在維護甚至開發那系統的語言已經沒人聽過了,那該如何是好?這時候就可以考慮使用Adpater模式,將新的邏輯資料轉換成舊系統格式輸入進去! 類別圖 Client : 呼叫端 Target : 要轉換的目標物件 Adapter : 適配器介面 可以使用硬轉換 (將每個對應的屬性或功能用Hard Code的方式配對) 也可以使用繼承的方式 (改寫) Adaptee : 要被轉換的物件 不管如何設計物件關係,適配器重點只有一個,創造一個Wrapper(包裝者)包裝要被轉換的物件,並且在此包裝者內撰寫轉換成目標物件的邏輯 範例 (英雄遊戲) 我們新上市的英雄遊戲因為大賣特賣,CEO為了持續增加業績開始併購其他遊戲,並且希望讓其他遊戲的角色可以和目前我們遊戲進行聯名,讓現在正在運行的遊戲玩家可以在遊戲內使用其他款遊戲的角色。 問題: 如何讓它款遊戲角色,與我們的英雄角色攻擊一致? 解決: 設計一個Adpater繼承我們Hero介面 在Adapter中實踐attack方法 attack時呼叫UnionHero(聯名英雄)的自己攻擊方法 interface Hero { void attack(); } class MyHero implements Hero { @Override public void attack() { System.out.println("My hero attack"); } } class UnionHero { public void touch() { System.out.println("Union Hero touch"); } } class HeroAdapter implements Hero { private UnionHero unionHero = null;

設計模式 - 原型模式 (Creational Patterns - Prototype Pattern)

原型模式的使用時機 當今天想要複製一個模型裡面的屬性時 並且複製的是原本物件的全部屬性 當今天new可能會造成危害時 設計方法 確保物件有clone方法 可以克制化或是繼承java.lang的Cloneable介面,直接使用Java物件之母的Object.clone功能 使用Object.clone功能必須以super的方式調度父類別 設計原型模式中心,可以進行調控(可能是工廠模式) 客戶端使用原型模式中心取出的物件,取代new出物件 範例 英雄訓練營可以訓練並且可以複製使用者覺得優秀的英雄,在此範例因為屬性過少所以感覺不到prototype的威力,當今天屬性變多後,使用prototype模式就不用慢慢地set屬性了。 class Hero implements Cloneable { //Prototype private String weapon; public String getWeapon() { return weapon; } public void setWeapon(String weapon) { this.weapon = weapon; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } class HeroCam { // Prototype registry public Hero makeHero() { return new Hero(); } public Hero cloneHero(Hero hero) throws CloneNotSupportedException { return (Hero) hero.clone(); } } public class Prototype { public static void main(String[] args) { HeroCam heroCam = new Hero

設計模式 - 單例模式 (Creational Patterns - Singleton Pattern)

前言 單例模式處處可見,而我個人目前使用單例模式的時機是,當今天確定此物件只需有一個時就使用single pattern。但是在某天有幸看到一篇文章評論Singleton濫用情形,開始思考單一Class的必要性。 單例模式特性 確保整個Application只會有此一個物件 為了確保整個Application只會有此物件,所以會需要static關鍵字,這也代表著會變成全域物件 單例模式會讓物件變成全域物件,這也是許多神人對與單例模式濫用批評的原因,會開放其實沒有必要變成全域的物件被接觸到 使用時機 當此物件是全域的,而且容易連續被使用以及需要強調單一則可以考慮使用。 Logger Configuration Cache 範例 Singleton分為兩種實踐方式,Lazy/Early懶漢與餓漢,實作Singleton最重要的是,多執行續時Singleton會不會有重複創建的問題,所以在Lazy實做時就會使用到最基本的Java Lock (synchronized),而Early使用到Final前綴字。 懶漢與餓漢差別 在於物件的初始化實機,懶就是晚一點餓就是一開始就來。 LazySingleton.java public class LazySingleton { private static volatile LazySingleton instance; private LazySingleton() {} public static LazySingleton getInstance(String value) { if (instance == null) { synchronized (LazySingleton.class) { if (instance == null) { instance = new LazySingleton(); } } } return instance; } } LazySingleton.java public class EarlySingleto

設計模式 - 建構者模式 (Creational Patterns - Build Pattern)

圖片
前言 此篇文章會介紹建構者模式(Build Pattern),並且會繼續使用前文 - 設計模式 - 工廠模式 (Creational Patterns - Factory Pattern) - 的英雄範例進行實作 甚麼是建構者模式? 我們回顧一下之前討論的工廠模式 工廠模式 - 封裝物件產出的邏輯 而工廠模式只關注,你要甚麼我就給你甚麼,對於產出的細節不透漏給client(呼叫此function)知道。 而建構者模式,則是將複雜的封裝流程切分,並且公開開發者認為client端可以掌控的邏輯method,而通常會需要使用到建構者模式也代表此物件的封裝過程比較複雜。 類別圖 Director負責透過Builder開放的方法組裝物件 Builder定義這個物件要開放的方法 範例 此範例主要是創建一個訓練營(Camp),然後跟去GameClient輸入的Build不同來創建一般或是高級的英雄。 Camp 在此是Director的角色 因為範例比較簡單所以感受不太到Builder的威力,若是未來如同真的遊戲般包含眼睛、眼球、身高、體重等等屬性,就可以感受到Builder的重要。 package com.design.pattern.creational.factory.builder; import java.util.Scanner; class Hero { String hair; String body; public void setHair(String hair) { this.hair = hair; } public void setBody(String body) { this.body = body; } } abstract class HeroBuilder { protected Hero hero; public void createHero() { hero = new Hero(); } public Hero getHero() { return hero; } public abstract void setHai

設計模式 - 工廠模式 (Creational Patterns - Factory Pattern)

圖片
前言 這篇文章會介紹三個最常使用的工廠模式方法,分別是 Simple Factory (簡單工廠) Abstract Factory (抽象工廠) Factory Method (工廠方法) 其中最容易讓人搞混的是,Abstract Factory和Factory Method,不過對我來說何必太過糾結於這兩個的概念,工廠模式最主要的核心原理就是將你創造物件的邏輯隱藏起來,不向客戶端顯示,我覺得只要知道這個概念就夠了,接下來會介紹這三個種類的工廠模式。 Factory Pattern 工廠模式 Simple Factory 簡單工廠 簡單工廠是工廠模式的第一步,也是工廠模式最基本的核心概念實踐,主要解決的問題是 將創建物件邏輯抽離 解偶Class的複雜度 Class Diagram 將封裝物件邏輯抽出寫成Simple Factory 產出父類別物件的物件 範例 在這個範例我們希望將戰士與魔法師遊戲創造英雄的邏輯抽出並且寫成靜態工廠,戰士與魔法師都是英雄並且’目前’只能進行攻擊,程式碼如下 Interface Hero public interface Hero { void attack(); } Magician.class public class Magician implements Hero { @Override public void attack() { System.out.println("Use magic to attack"); } } Warrior.class public class Warrior implements Hero { @Override public void attack() { System.out.println("Use sword to attack"); } } HeroFactory.class public class HeroFactory { public Hero makeHero(HeroType heroType) { if (heroType.equals(HeroType.MA