2023-08-04 09:22:51來源:宇宙一碼平川
工廠模式是最常見的一種創(chuàng)建型設(shè)計(jì)模式,通常說的工廠模式指的是工廠方法模式,是使用頻率最高的工廠模式。簡(jiǎn)單工廠模式又稱為靜態(tài)工廠方法模式,不屬于GoF 23種設(shè)計(jì)模式,它屬于類創(chuàng)建型模式,是其它工廠模式的入門。
2游戲工廠的設(shè)計(jì)ONEGAME游戲公司計(jì)劃開發(fā)一條游戲生產(chǎn)線,該生產(chǎn)線可以向玩家提供不同類型的游戲,例如:RGP游戲、MMORGP游戲、MOBA游戲以及FPS游戲等。為了提供這些游戲,游戲公司需要?jiǎng)?chuàng)建一個(gè)游戲工廠,來創(chuàng)建這些游戲的實(shí)例。
ONEGAME游戲公司提出了初始設(shè)計(jì)方案,就是將所有類型的游戲的實(shí)現(xiàn)代碼封裝到一個(gè)Game類中,然后通過Game工廠來創(chuàng)建實(shí)例。實(shí)現(xiàn)代碼如下:
【資料圖】
class Game{ private type: string;//游戲類別 constructor(type: string, data: any) { this.type = type; if(type.toLocaleLowerCase() === "fps"){ // 初始化FPS游戲 }else if(type.toLocaleLowerCase() === "rpg"){ // 初始化RPG游戲 }else if(type.toLocaleLowerCase() === "moba"){ // 初始化MOBA游戲 } } play(){ if(this.type.toLocaleLowerCase() === "fps"){ // 玩FPS游戲 }else if(this.type.toLocaleLowerCase() === "rpg"){ // 玩RPG游戲 }else if(this.type.toLocaleLowerCase() === "moba"){ // 玩MOBA游戲 } }}
上面的代碼實(shí)現(xiàn)了游戲的創(chuàng)建和玩游戲的功能,但是這樣的設(shè)計(jì)存在以下問題:
Game類的代碼會(huì)越來越臃腫,而且違反了單一職責(zé)原則,不利于代碼的維護(hù)和擴(kuò)展。在需要對(duì)Game類進(jìn)行擴(kuò)展新游戲的時(shí)候,需要對(duì)源碼進(jìn)行修改,這就違反了開閉原則。用戶只能通過new關(guān)鍵字來直接創(chuàng)建實(shí)例,而不是通過Game工廠來創(chuàng)建實(shí)例,耦合性高,對(duì)象創(chuàng)建和使用無法分離。為了解決上面的問題,我們可以對(duì)Game類進(jìn)行重構(gòu),將其拆分成多個(gè)游戲類,每個(gè)游戲類只負(fù)責(zé)自己的初始化和玩游戲的功能,這樣就可以避免代碼臃腫和違反單一職責(zé)原則的問題。但是這樣做還是無法解決對(duì)象創(chuàng)建和使用無法分離的問題,我們可以通過簡(jiǎn)單工廠模式來解決這個(gè)問題。
3簡(jiǎn)單工廠模式簡(jiǎn)單工廠的設(shè)計(jì)思想就是,將創(chuàng)建不同對(duì)象的相關(guān)的代碼封裝到不同的類中,即具體產(chǎn)品類,這樣就可以避免代碼的臃腫和違反單一職責(zé)原則的問題。將它們的公共代碼抽象到和封裝到一個(gè)抽象產(chǎn)品類中,每個(gè)具體類都是抽象產(chǎn)品類的子類。然后通過一個(gè)工廠類來創(chuàng)建這些具體產(chǎn)品類的實(shí)例,通過傳入的參數(shù)不同創(chuàng)建對(duì)應(yīng)的具體產(chǎn)品對(duì)象。
什么是簡(jiǎn)單工廠模式簡(jiǎn)單工廠模式:定義一個(gè)工廠類,通過傳入?yún)?shù)來創(chuàng)建不同的具體產(chǎn)品類的實(shí)例,被創(chuàng)建的實(shí)例都具有共同的父類。
簡(jiǎn)單工廠模式結(jié)構(gòu)包括三個(gè)角色:
工廠類:創(chuàng)建具體產(chǎn)品類的實(shí)例的工廠類,負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建具體產(chǎn)品實(shí)例的內(nèi)部邏輯。工廠類可以被外界直接調(diào)用,創(chuàng)建所需的產(chǎn)品對(duì)象。抽象產(chǎn)品類:創(chuàng)建具體產(chǎn)品類的實(shí)例的抽象產(chǎn)品類,它是需要工廠類所創(chuàng)建的所有具體產(chǎn)品類的公共父類,封裝了各種產(chǎn)品對(duì)象的公有方法。具體產(chǎn)品類:具體產(chǎn)品類的實(shí)例,是簡(jiǎn)單工廠模式的創(chuàng)建目標(biāo),它繼承抽象產(chǎn)品類的公共父類,所有被創(chuàng)建的對(duì)象都是這個(gè)產(chǎn)品對(duì)應(yīng)的具體產(chǎn)品類的實(shí)例。使用簡(jiǎn)單工廠模式優(yōu)化上面的代碼,以實(shí)現(xiàn)一個(gè)游戲工廠為為例,實(shí)現(xiàn)可以生產(chǎn)不同類型的游戲?yàn)槟康摹J紫榷x一個(gè)抽象產(chǎn)品類Game,然后定義具體產(chǎn)品類FPSGame、RPGGame、MOBAGame,最后定義一個(gè)工廠類GameFactory,通過傳入不同的參數(shù)來創(chuàng)建不同的游戲?qū)嵗?/p>
// 游戲接口:抽象產(chǎn)品類interface Game { play(): void;}// 各種游戲的具體實(shí)現(xiàn)類:具體產(chǎn)品類// FPS游戲class FPSGame implements Game{ play() { console.log("FPS游戲"); }}// RPG游戲class RPGGame implements Game { play() { console.log("RPG游戲"); }}// MOBA游戲class MOBAGame implements Game { play() { console.log("MOBA游戲"); }}// 游戲工廠:創(chuàng)建具體產(chǎn)品類的實(shí)例的工廠類class GameFactory { static createGame(type: string): Game { this.type = type; switch (this.type) { case "RPG": return new RPGGame(); case "MOBA": return new MOBAGame(); case "FPS": return new FPSGame(); default: throw new Error("Unknown game type"); } }}
用戶實(shí)際使用創(chuàng)建對(duì)應(yīng)的游戲:
// 獲取RGP游戲const rgpGame = GameFactory.createGame("RPG");rgpGame.play();// 獲取MOBA游戲const mobaGame = GameFactory.createGame("MOBA");mobaGame.play();
在實(shí)際使用中,客戶端代碼只需要傳入類型參數(shù),就可以獲取得到對(duì)應(yīng)的游戲?qū)ο?,而不需要關(guān)系對(duì)象的具體實(shí)現(xiàn)。這就符合簡(jiǎn)單工廠模式的設(shè)計(jì)思想。
簡(jiǎn)單工廠模式的優(yōu)點(diǎn)封裝實(shí)例化過程:簡(jiǎn)單工廠模式在一個(gè)工廠類中封裝了實(shí)例化對(duì)象的過程,創(chuàng)建對(duì)象的細(xì)節(jié)被隱藏在工廠類中,外界無需關(guān)心對(duì)象是如何被創(chuàng)建出來的。定義統(tǒng)一接口:工廠類所創(chuàng)建的對(duì)象都實(shí)現(xiàn)了一個(gè)共同的接口,對(duì)外提供一致的使用方式。通過參數(shù)創(chuàng)建不同實(shí)例:客戶端只需要傳入不同的參數(shù)給工廠類,就可以獲取不同的對(duì)象實(shí)例,而不需要知道具體類名。實(shí)現(xiàn)解耦:簡(jiǎn)單工廠模式實(shí)現(xiàn)了客戶端與產(chǎn)品類的解耦,客戶端不需要知道所創(chuàng)建對(duì)象的具體實(shí)現(xiàn),只需要知道參數(shù)即可。優(yōu)化開閉原則:當(dāng)需要新增一個(gè)產(chǎn)品類時(shí),只需要實(shí)現(xiàn)統(tǒng)一接口,然后在工廠類中添加對(duì)應(yīng)類型即可,無需修改客戶端代碼。高內(nèi)聚,低耦合:每個(gè)產(chǎn)品類只關(guān)心自己的功能實(shí)現(xiàn),不關(guān)心實(shí)例化過程;客戶端不依賴具體類。使代碼內(nèi)聚性高、耦合度低。4簡(jiǎn)單工廠模式的優(yōu)化使用泛型優(yōu)化工廠類在上面的實(shí)現(xiàn)中,工廠類的創(chuàng)建方法返回的是Game接口類型,缺點(diǎn)是客戶端得到的對(duì)象類型信息不全,對(duì)此可以使用泛型來改進(jìn):
// 游戲接口:抽象產(chǎn)品類interface Game { play(): void;}class FPSGame implements Game { //...}class RPGGame implements Game { //...}class MOBAGame implements Game { //...}class GameFactory{ static createGame(type: string): T{ //... }}
這樣在客戶端代碼得到的對(duì)象類型信息更加準(zhǔn)確。
const rgpGame = GameFactory.createGame("RPG");// rgpGame的類型是RPGGame,而不是Game
使用泛型優(yōu)化工廠類的優(yōu)化上面的代碼中,所有的產(chǎn)品類都需要實(shí)現(xiàn) Game 接口,這樣會(huì)存在代碼重復(fù)的問題。我們可以引入一個(gè)泛型接口 IGame來改進(jìn):
interface IGame { play(): void; info(): T; }class RPGGame implements IGame { play() { // ... } info() { return "RPG"; }}class MOBAGame implements IGame { play() { // ... } info() { return "MOBA"; }}class FPSGame implements IGame { // ...}
這樣每個(gè)產(chǎn)品類就可以定制自己的 info 方法返回值類型了。
使用抽象類改進(jìn)產(chǎn)品類上面的代碼還存在問題:所有產(chǎn)品類都需要實(shí)現(xiàn) play 方法,這會(huì)導(dǎo)致重復(fù)代碼。我們可以使用抽象類來解決這個(gè)問題:
abstract class GameBase { play() { // 默認(rèn)游戲邏輯 } }class RPGGame extends GameBase implements IGame { info() { return "RPG"; }}class MOBAGame extends GameBase implements IGame { // ...}class FPSGame extends GameBase implements IGame { // ...}
這樣產(chǎn)品類就不需要重復(fù)實(shí)現(xiàn) play 方法了,只需要繼承 GameBase 并實(shí)現(xiàn) info 方法即可。
使用配置文件創(chuàng)建工廠類上面的代碼中,工廠類的創(chuàng)建方法需要傳入一個(gè)類型參數(shù),這樣會(huì)導(dǎo)致客戶端代碼需要知道具體的類型參數(shù),這樣就會(huì)破壞簡(jiǎn)單工廠模式的封裝性。我們可以使用配置文件來解決這個(gè)問題:
class GameConfig { static gameTypes = { "RPG": RPG, "MOBA": MOBA, "FPS": FPS }}
工廠類讀取配置創(chuàng)建對(duì)象:
class GameFactory { static createGame(type: string) { const Constructor = GameConfig.gameTypes[type]; if (!Constructor) { throw new Error("Unknown type"); } return new Constructor(); }}
這樣當(dāng)需要新增游戲類型時(shí),只需要在配置類中添加新的類型和類即可,工廠類的代碼無需修改。
利用依賴注入實(shí)現(xiàn)解耦我們還可以通過依賴注入進(jìn)一步解耦:
@injectable()class GameFactory { constructor( @inject(GameConfig.gameTypes.RPG) private rpgGame: Game, @inject(GameConfig.gameTypes.MOBA) private mobaGame: Game, @inject(GameConfig.gameTypes.FPS) private fpsGame: Game ) {} createGame(type: string) { switch(type) { // ... } }}
這樣工廠類不再負(fù)責(zé)創(chuàng)建對(duì)象,而是通過注入的方式獲取對(duì)象實(shí)例,大大提升了靈活性。
5完整代碼示例下面是使用 TypeScript 深入解析簡(jiǎn)單工廠模式的示例,通過工廠類和產(chǎn)品類的抽象與解耦,可以實(shí)現(xiàn)創(chuàng)建對(duì)象邏輯的集中和優(yōu)化,提高代碼的靈活性和擴(kuò)展性。TypeScript 通過接口、泛型和抽象類等特性增強(qiáng)了簡(jiǎn)單工廠模式的實(shí)現(xiàn)。掌握設(shè)計(jì)模式對(duì)編寫優(yōu)雅可擴(kuò)展的 TypeScript 代碼很有幫助。
// 游戲接口interface Game { play(): void;}// 泛型游戲接口 interface IGame { play(): void; info(): T;}// 抽象游戲類abstract class GameBase { play() { console.log("Playing game..."); }}// RPG游戲類class RPG extends GameBase implements IGame { info() { return "RPG"; }}// MMORPG游戲類 class MMORPG extends GameBase implements IGame { info() { return "MMORPG"; }}// FPS游戲類class FPS extends GameBase implements IGame { info() { return "FPS"; }}// 配置類class GameConfig { static gameTypes = { "RPG": RPG, "MMORPG": MMORPG, "FPS": FPS }}// 工廠類class GameFactory { static createGame(type: string) { const Constructor = GameConfig.gameTypes[type]; if (!Constructor) { throw new Error("Unknown type"); } return new Constructor(); }}// 客戶端const rpgGame = GameFactory.createGame("RPG");rpgGame.play();console.log(rpgGame.info());const fpsGame = GameFactory.createGame("FPS");fpsGame.play();console.log(fpsGame.info());
6簡(jiǎn)單工廠模式和單例模式的區(qū)別1. 用途不同簡(jiǎn)單工廠模式是一種創(chuàng)建對(duì)象的設(shè)計(jì)模式,它通過工廠類來創(chuàng)建產(chǎn)品對(duì)象,主要目的是將對(duì)象創(chuàng)建的過程封裝起來,便于管理和維護(hù)。
而單例模式是一種確保某個(gè)類只有一個(gè)實(shí)例的設(shè)計(jì)模式,它的目的是在整個(gè)軟件系統(tǒng)中,對(duì)某個(gè)類只創(chuàng)建一個(gè)對(duì)象實(shí)例,避免浪費(fèi)資源。
2. 實(shí)現(xiàn)方式不同簡(jiǎn)單工廠模式是通過工廠類的靜態(tài)方法創(chuàng)建對(duì)象實(shí)例,可以創(chuàng)建多個(gè)實(shí)例。
單例模式是在類中定義一個(gè)靜態(tài)變量保存單例實(shí)例,并通過一個(gè)靜態(tài)方法來獲取這個(gè)實(shí)例,確保只創(chuàng)建一個(gè)實(shí)例。
3. 使用場(chǎng)景不同簡(jiǎn)單工廠模式用于創(chuàng)建同一類產(chǎn)品的不同對(duì)象實(shí)例,客戶端無需知道具體產(chǎn)品類的類名。
單例模式用于創(chuàng)建對(duì)唯一實(shí)例有需求的對(duì)象,如線程池、緩存、日志對(duì)象等。
小結(jié)一下,簡(jiǎn)單工廠模式關(guān)注創(chuàng)建不同實(shí)例,單例模式關(guān)注如何只創(chuàng)建一個(gè)實(shí)例。二者解決的問題和應(yīng)用場(chǎng)景不同,但可以結(jié)合使用,工廠類可以返回單例對(duì)象。
7總結(jié)通過上面的示例,我們使用 TypeScript 從多個(gè)方面對(duì)簡(jiǎn)單工廠模式進(jìn)行了深入解析,包括:
使用泛型優(yōu)化工廠方法的返回類型使用泛型接口減少產(chǎn)品類代碼重復(fù)使用抽象類提取產(chǎn)品類公共代碼使用配置文件動(dòng)態(tài)創(chuàng)建產(chǎn)品類實(shí)例簡(jiǎn)單工廠模式的優(yōu)點(diǎn):
將對(duì)象創(chuàng)建的過程封裝在工廠類中,實(shí)現(xiàn)了解耦客戶端無須知道所創(chuàng)建具體產(chǎn)品類的類名可以方便地?cái)U(kuò)展新的具體產(chǎn)品類簡(jiǎn)單工廠模式的缺點(diǎn):
工廠類職責(zé)較重,所有產(chǎn)品創(chuàng)建邏輯都集中在工廠類如果產(chǎn)品類型較多,工廠類會(huì)變得很復(fù)雜擴(kuò)展新的產(chǎn)品困難,需要修改工廠類代碼簡(jiǎn)單工廠模式通過工廠類和產(chǎn)品類的解耦,可以實(shí)現(xiàn)創(chuàng)建對(duì)象邏輯的集中化和優(yōu)化,是非常常用和靈活的一種設(shè)計(jì)模式。TypeScript 通過接口、泛型和抽象類等特性,可以更優(yōu)雅地實(shí)現(xiàn)簡(jiǎn)單工廠模式,提高代碼的復(fù)用性和擴(kuò)展性。
關(guān)鍵詞:
1寫在前面工廠模式是最常見的一種創(chuàng)建型設(shè)計(jì)模式,通常說的工廠模式指
人工智能在企業(yè)中的作用越來越突出,并且在不久的將來可能塑造創(chuàng)新的工
8月4日,生意社錦綸DTY基準(zhǔn)價(jià)為18080 00元 噸,與本月初持平。錦綸DTY
整理 海報(bào)羊城晚報(bào)全媒體記者朱嘉樂▌【視頻】“薄殼米之鄉(xiāng)”汕頭澄海
大家好,今日關(guān)于【洪水對(duì)上游還是下游影響大洪水下游居民撈“盲盒”是
①②③①繞獨(dú)木橋②翻越障礙③跨越壕溝李林陽(yáng)劉子靖作
1、隨著人們生活要求的提高,裝修時(shí)都想設(shè)計(jì)一間干凈獨(dú)立的洗浴空間,
《人間煙火》帶來的后續(xù)影響波及了王楚然,因?yàn)閯≈?ldquo;許沁”一角并不討
日前,廣東省紀(jì)委監(jiān)委公開通報(bào)8起鄉(xiāng)村振興領(lǐng)域違紀(jì)違法案件。其中,佛
本刊編輯部|齊永超近來,消費(fèi)板塊行情回暖,消費(fèi)領(lǐng)域中的白酒股也迎來
三孚新科近日接受機(jī)構(gòu)調(diào)研時(shí)表示,目前公司設(shè)備保守產(chǎn)能約為10臺(tái) 月。
▼01 6【問】T9900:房妹子,丹霞云邸和特房錦繡碧湖哪個(gè)好?【答】房
山水相依村莊秀麗,屋舍儼然熠熠生輝,房前屋后綠樹環(huán)繞,村頭小亭品茗
從《2001太空漫游》(2001:ASpaceOdyssey)中HAL9000令人不寒而栗的宣
汽車時(shí)光網(wǎng)報(bào)道:日前,比亞迪汽車近日發(fā)布了備受矚目的7月銷量數(shù)據(jù),