iOS 24種設(shè)計模式 - Swift

設(shè)計模式是一種被廣泛應(yīng)用于軟件工程的解決問題的方法浇冰。

它們可以幫助開發(fā)人員提高代碼的可復(fù)用性贬媒、可維護性和可擴展性。設(shè)計模式的使用可以讓開發(fā)人員更加專注于解決實際的問題而不是去考慮如何實現(xiàn)它們肘习。這些設(shè)計模式可以分為三種類型际乘,分別是:

1. 創(chuàng)建型模式(Creational Patterns)

2. 結(jié)構(gòu)型模式(Structural Patterns)

3. 行為型模式(Behavioral Patterns)

同時設(shè)計模式有七大原則:

1 總原則:開閉原則(Open/Closed Principle脖含,OCP)

開閉原則的思想是:當新的需求出現(xiàn)時器赞,應(yīng)該盡可能地通過增加新的代碼來滿足這些需求港柜,而不是直接修改現(xiàn)有代碼。

通過增加新的代碼氯夷,可以保證現(xiàn)有代碼的穩(wěn)定性腮考,同時也可以提高代碼的可維護性和可擴展性

例子

在上述代碼中馅闽,我們采用了裝飾器模式來實現(xiàn)開閉原則福也。首先,我們定義了一個抽象類CarDecorator赘来,用于表示所有的汽車裝飾器。然后忧风,我們定義了一個具體裝飾器AutoDriveDecorator,用于添加自動駕駛功能缘厢。在AutoDriveDecorator中贴硫,我們重寫了startEngine方法,并在其中添加了自動駕駛功能汁尺。最后痴突,我們可以通過創(chuàng)建一個AutoDriveDecorator對象來給汽車添加自動駕駛功能,而不需要修改原有的Car類如迟。具體地殷勘,我們可以通過以下代碼來實現(xiàn):

通過擴展現(xiàn)有代碼來滿足新的需求,而不需要修改原有的代碼贤斜。這種方式可以保證原有代碼的結(jié)構(gòu)和穩(wěn)定性,同時也使得代碼更加易于擴展和維護锁荔。

2 單一職責原則(Single responsibility principle, SRP)

不要存在多于一個導(dǎo)致類變更的原因,也就是說每個類應(yīng)該實現(xiàn)單一的職責恬总,否則就應(yīng)該把類拆分.

單一職責原則可以幫助我們更好地組織代碼壹堰,使得代碼易于維護和擴展记劈。通過遵循單一職責原則,我們可以使代碼更加模塊化刽射,每個模塊只負責一個職責,易于測試和重用摹恰。同時俗慈,當需求變化時,我們也可以更容易地對代碼進行修改酣溃,而不會影響到其他模塊赊豌。

上面這個示例中,我們將 Employee 類的兩個職責分別拆分為 SalaryCalculator 類和 TaskPerformer類。這樣每個類只負責單一職責拢切,易于維護和擴展,符合單一職責原則主穗。

使用:

在實際開發(fā)中争拐,我們可以通過以下幾個方面來遵循單一職責原則:

分離職責:將一個類中的不同職責拆分成獨立的類或模塊,使每個類或模塊只負責單一職責绑雄。

抽象接口:使用抽象接口或協(xié)議來定義類或模塊之間的交互方式万牺,避免直接依賴具體的實現(xiàn)。

限制類的大小:盡可能限制類的大小珊楼,避免過于復(fù)雜的類厕宗,可以通過拆分、繼承佑惠、組合等方式來實現(xiàn)。

定期重構(gòu):定期地對代碼進行重構(gòu)贞奋,去除重復(fù)代碼特愿,將代碼按照職責進行組織,使得代碼更易于維護和擴展目养。

總之,遵循單一職責原則是一個重要的設(shè)計原則匈勋,可以幫助我們寫出更加模塊化洽洁、可維護和可擴展的代碼饿自。

3 里氏替換原則(Liskov Substitution Principle, LSP)

核心:子類對象可以替換父類對象出現(xiàn)在程序中昭雌,而不影響程序的正確性。

這個原則可以提高程序的靈活性和可維護性,使程序更容易擴展和修改局雄。

例子

假設(shè)有一個Animal 類和一個Dog類,Dog 類是Animal 類的子類。Animal 類有一個run 方法飘言,它可以讓動物奔跑倒源;Dog 類繼承了Animal 類热某,并重寫了run 方法。

根據(jù)里氏替換原則,我們可以將Dog 對象賦值給Animal 對象,而程序仍然可以正常運行倦蚪。例如:

4 依賴倒轉(zhuǎn)原則(Dependency Inversion Principle)

官方解釋是:高層模塊不應(yīng)該依賴低層模塊个束,二者都應(yīng)該依賴其抽象脓钾,抽象不應(yīng)該依賴細節(jié)捶枢,細節(jié)應(yīng)該依賴抽象。

其實核心就是面向接口編程胯努,而不是面向?qū)崿F(xiàn)編程蒲讯。

這樣的好處就是通過抽象接口溉箕,可以減少模塊間的依賴關(guān)系晌畅,提高系統(tǒng)的靈活性和可維護性氓癌。

例子

實現(xiàn):

5 接口隔離原則(Interface Segregation Principle)

一個類不應(yīng)該強迫其它類依賴它們不需要使用的方法,也就是說才顿,一個類對另一個類的依賴應(yīng)該建立在最小的接口上腰池。

核心思想是:一個類應(yīng)該只提供其它類需要使用的方法,而不應(yīng)該強迫其它類依賴于它們不需要使用的方法跨跨。

通過遵守接口隔離原則,可以提高系統(tǒng)的靈活性德谅、可維護性和可擴展性慰技。

例子

實現(xiàn):

接口隔離原則的核心是為了讓接口具備高內(nèi)聚性低耦合性艾帐。

如果一個接口過于臃腫,就需要將其拆分成多個小的接口,使得每個接口中只包含必要的方法今野。這樣的好處是:

接口更加具有內(nèi)聚性:每個接口只需要關(guān)注自己的功能宰睡,而不需要關(guān)注其他接口中的方法,因此能夠使接口更加專注和具有內(nèi)聚性。

接口之間的耦合度更低:每個接口只依賴于必要的方法孩等,而不依賴于其他不必要的方法,因此能夠使接口之間的耦合度更低。

代碼的復(fù)用性更高:每個接口只包含必要的方法逝薪,因此能夠使得代碼的復(fù)用性更高隅要,也能夠提高代碼的可讀性和可維護性。

6 迪米特法則(最少知道原則)(The Law of Demeter, LoD)

一個類對自己依賴的類知道的越少越好董济。無論被依賴的類多么復(fù)雜谴轮,都應(yīng)該將邏輯封裝在方法的內(nèi)部雌续,通過public方法提供給外部鸽心。

最少知道原則的另一個表達方式是:只與直接的朋友通信。

類之間只要有耦合關(guān)系最住,就叫朋友關(guān)系。耦合分為依賴、關(guān)聯(lián)府树、聚合垄潮、組合等。我們稱出現(xiàn)為成員變量、方法參數(shù)、方法返回值中的類為直接朋友。局部變量戏阅、臨時變量則不是直接的朋友芭逝。

例子

在上面的代碼示例中,每個類都只和自己直接的朋友進行通信疫稿,遵循了最少知道原則腾降。User 類只依賴于 ShoppingCart 類,而不直接依賴于 Goods 類逮光。ShoppingCart 類只依賴于Goods 類。這樣,當 Goods 類發(fā)生變化時译秦,只會對 ShoppingCart 類產(chǎn)生影響,而不會對 User 類產(chǎn)生影響。 以下為實現(xiàn)代碼:

7 合成復(fù)用原則(Composite Reuse Principle, CRP)

當我們需要在一個類中使用另一個類的功能時猖吴,有兩種方式:繼承和合成/聚合拗引。

繼承是指子類繼承父類的屬性和方法哼凯,可以重寫父類的方法,但也存在耦合性較高的問題,當父類修改時著拭,子類也需要相應(yīng)地修改鄙币。

合成/聚合是指一個類作為另一個類的成員變量咳燕,通過調(diào)用該成員變量的方法來實現(xiàn)該類的功能表制。

組合和繼承都可以用來實現(xiàn)代碼的復(fù)用,但是它們之間有著不同的優(yōu)缺點。在使用繼承時摧找,我們需要注意代碼的耦合度,避免代碼的重復(fù)和臃腫赃承。在使用組合時捉撮,我們需要將代碼分解為更小的組件灼舍,并注意組件之間的接口設(shè)計末捣。

對設(shè)計模式七大原則的理解,學習第一種模式:創(chuàng)建型模式郭赐。

在面向?qū)ο缶幊讨校瑒?chuàng)建型模式是用于實例化對象的設(shè)計模式。它們可以幫助我們有效地創(chuàng)建對象,而不會使代碼變得復(fù)雜或難以維護霞掺。

在實際的開發(fā)過程中剩彬,正確使用創(chuàng)建型模式可以帶來許多好處:

降低耦合性:創(chuàng)建型模式可以將對象的創(chuàng)建過程與使用過程分離升酣,從而降低對象之間的耦合性。這使得代碼更加靈活和易于維護。

提高復(fù)用性:創(chuàng)建型模式可以將對象的創(chuàng)建過程抽象出來炮沐,并使其可復(fù)用。這使得我們可以在整個應(yīng)用程序中共享對象的創(chuàng)建邏輯商乎,從而提高了代碼的復(fù)用性央拖。

隱藏對象的創(chuàng)建細節(jié):使用創(chuàng)建型模式可以將對象的創(chuàng)建細節(jié)隱藏在模式內(nèi)部门驾,使得客戶端無需知道對象創(chuàng)建的具體細節(jié)哎迄。這使得代碼更加簡潔、清晰粟按,并提高了代碼的可讀性抹凳。

管理對象的生命周期:某些創(chuàng)建型模式(如工廠方法模式)可以管理對象的生命周期遏餐,從而確保對象的正確創(chuàng)建、使用和銷毀赢底。

改善代碼的可測試性:使用創(chuàng)建型模式可以使代碼更加易于測試失都。由于對象的創(chuàng)建過程被抽象出來并且與使用過程分離,因此可以更容易地編寫測試用例

常見的創(chuàng)建型模式:

1.簡單工廠模式(Simple Factory Pattern)

2.工廠方法模式(Factory Method Pattern)

3.抽象工廠模式(Abstract Factory Pattern)

4.單例模式(Singleton Pattern)

5.原形模式(Prototype Pattern)

6.建造者模式(Builder Pattern)

一幸冻、簡單工廠模式(Simple Factory Pattern)

在工廠模式中粹庞,我們在創(chuàng)建對象時,通過使用一個共同的接口來創(chuàng)建不同的對象洽损,而無需暴露對象的創(chuàng)建邏輯庞溜。

在簡單工廠模式中,我們定義一個工廠類碑定,該工廠類負責創(chuàng)建各種對象流码。我們只需調(diào)用工廠類的方法即可獲取需要的對象又官,而無需直接使用 new 關(guān)鍵字創(chuàng)建對象。這樣可以使代碼更加靈活和易于維護漫试,因為如果我們想要更改創(chuàng)建對象的邏輯六敬,只需要更改工廠類中的代碼即可。

假設(shè)我們有一個 Animals 類和兩個子類 Dogs 和 Cats驾荣,我們想要使用工廠模式來創(chuàng)建它們的實例:

在上面的代碼中外构,我們定義了一個 Animals類和兩個子類 Dogs 和 Cats。我們還定義了一個 AnimalFactory 工廠類播掷,其中有一個 createAnimalWithType方法典勇,該方法根據(jù)傳入的 type 參數(shù)來創(chuàng)建不同類型的動物對象。當我們需要創(chuàng)建動物對象時叮趴,只需調(diào)用 AnimalFactory 的 createAnimalWithType方法割笙,傳入所需的類型,即可獲取相應(yīng)的對象眯亦。

通過這種方式伤溉,我們可以在不暴露對象創(chuàng)建邏輯的情況下創(chuàng)建不同類型的對象,并且可以輕松地添加新類型的動物妻率,只需在 AnimalFactory 中添加相應(yīng)的創(chuàng)建邏輯即可乱顾。

二、工廠方法模式(Factory Method Pattern)

工廠方法模式和簡單工廠模式類似宫静。

簡單工廠模式和工廠方法模式的區(qū)別在于創(chuàng)建對象的方式走净。

簡單工廠模式使用一個共享的工廠類來創(chuàng)建所有類型的對象,客戶端通過傳遞參數(shù)來指定要創(chuàng)建的對象類型孤里。

而工廠方法模式將每種具體產(chǎn)品的創(chuàng)建邏輯委托給對應(yīng)的工廠類伏伯,客戶端通過選擇特定的工廠類來創(chuàng)建特定類型的對象

簡單工廠模式適用于對象類型較少且創(chuàng)建邏輯相對簡單的情況捌袜。工廠方法模式適用于對象類型較多或創(chuàng)建邏輯較為復(fù)雜的情況说搅,它更符合開閉原則,允許新增具體產(chǎn)品和工廠類虏等,而無需修改現(xiàn)有代碼弄唧。

三、抽象工廠模式(Abstract Factory Pattern)

它提供一個接口用于創(chuàng)建一系列相關(guān)或依賴對象的家族霍衫,而不需要明確指定它們的具體類候引。

在抽象工廠模式中,抽象工廠接口定義了一組方法敦跌,用于創(chuàng)建一系列相關(guān)對象的工廠澄干。這些相關(guān)對象可以是一組不同但相關(guān)的對象,例如在GUI界面中,按鈕傻寂、標簽、輸入框等都屬于相關(guān)的對象家族携兵,它們通常會按照某種風格設(shè)計疾掰,如iOS 風格、Android 風格等徐紧。在抽象工廠模式中静檬,每個具體工廠類都實現(xiàn)了這個抽象工廠接口,以便能夠按照某種特定的規(guī)則或風格創(chuàng)建相關(guān)對象的家族并级。

可以說抽象工廠模式是工廠模式的一個擴展拂檩,它提供了一種更高層次的抽象,能夠創(chuàng)建一組相關(guān)的對象家族嘲碧,而不僅僅是一個對象稻励。

同時,抽象工廠模式也遵循了開閉原則愈涩,因為它允許在不修改現(xiàn)有代碼的情況下添加新的具體工廠和產(chǎn)品系列望抽,從而提高了代碼的可維護性和可擴展性。

例子:

我們要寫兩個風格的UI履婉,分別是iOS 風格和Android 風格煤篙,首先,我們定義一個抽象工廠接口毁腿,它包含兩個方法:創(chuàng)建按鈕和創(chuàng)建標簽辑奈。然后,我們創(chuàng)建兩個具體工廠類已烤,它們實現(xiàn)了這個抽象工廠接口鸠窗,并分別創(chuàng)建了iOS 和Android 風格的按鈕和標簽。

最后胯究,我們使用這些具體工廠類來創(chuàng)建具體的按鈕和標簽對象塌鸯,而不需要知道它們的具體類。

通過使用抽象工廠模式唐片,我們可以輕松地擴展工廠和產(chǎn)品系列丙猬,而不需要修改現(xiàn)有的客戶端代碼。例如费韭,我們可以創(chuàng)建一個新的具體工廠類茧球,以創(chuàng)建Windows風格的按鈕和標簽。

抽象工廠模式的優(yōu)點:

將對象的創(chuàng)建與使用分離星持,客戶端只需要知道如何使用這些對象抢埋,而不需要關(guān)心它們是如何創(chuàng)建的。

可以輕松地在程序中切換不同的產(chǎn)品簇,只需要改變具體工廠類即可揪垄,無需修改客戶端代碼穷吮。

可以確保一組相關(guān)的產(chǎn)品只能由同一個工廠創(chuàng)建,避免了不同產(chǎn)品之間的兼容性問題饥努。

可以提高代碼的擴展性和可維護性捡鱼,如果需要添加一個新的產(chǎn)品簇,只需要添加一個新的具體工廠類即可酷愧。

抽象工廠模式的缺點:

新增加一個產(chǎn)品簇比較困難驾诈,需要修改抽象工廠接口和所有的具體工廠類。

如果產(chǎn)品簇過多溶浴,會導(dǎo)致抽象工廠接口和所有的具體工廠類變得非常復(fù)雜乍迄,不易維護。

由于抽象工廠模式需要定義抽象工廠接口和抽象產(chǎn)品接口士败,因此代碼的抽象層次比較高闯两,有一定的學習成本。

總之谅将,抽象工廠模式適合于那些需要一整套一起使用的對象(比如QQ 換皮膚)生蚁,并且需要能夠方便地切換不同的產(chǎn)品簇的場景,但是如果產(chǎn)品簇過多或者需要頻繁添加新的產(chǎn)品簇戏自,可能會導(dǎo)致代碼變得復(fù)雜邦投。

“產(chǎn)品簇:指的是一組相關(guān)聯(lián)的產(chǎn)品,它們通常用于解決同一個問題或者滿足同一種需求擅笔。例如志衣,在電商網(wǎng)站上,一個產(chǎn)品簇可以包括商品猛们、訂單念脯、收貨地址等多個相關(guān)聯(lián)的產(chǎn)品;在游戲開發(fā)中弯淘,一個產(chǎn)品簇可以包括角色绿店、武器、裝備等多相關(guān)聯(lián)的產(chǎn)品庐橙〖傥穑”

四、單例模式(Singleton Pattern)

單例模式是一種創(chuàng)建對象的設(shè)計模式态鳖,它確保一個類只有一個實例转培,并提供全局訪問點以訪問該實例。

單例模式通常用于需要全局訪問且只需要一個實例的場景浆竭。下面是一些常見的用例:

配置對象:在應(yīng)用程序中浸须,可能需要一個全局配置對象惨寿,用于存儲應(yīng)用程序的設(shè)置和配置選項。使用單例模式可以確保只有一個配置對象删窒,并使其在整個應(yīng)用程序中易于訪問裂垦。

數(shù)據(jù)庫連接對象:在使用數(shù)據(jù)庫的應(yīng)用程序中,可能需要一個全局的數(shù)據(jù)庫連接對象肌索,用于執(zhí)行查詢和更新操作蕉拢。使用單例模式可以確保只有一個數(shù)據(jù)庫連接對象,并使其在整個應(yīng)用程序中易于訪問驶社。

日志對象:在應(yīng)用程序中,可能需要一個全局的日志對象测萎,用于記錄應(yīng)用程序的運行時信息亡电。使用單例模式可以確保只有一個日志對象,并使其在整個應(yīng)用程序中易于訪問硅瞧。

總之份乒,單例模式在需要全局訪問且只需要一個實例的場景下非常有用。但是腕唧,使用單例模式也存在一些缺點或辖,例如可能導(dǎo)致代碼耦合性增強、單例對象的生命周期可能過長等問題枣接。因此颂暇,在使用單例模式時需要謹慎考慮其適用性和使用方式。

五但惶、原形模式(Prototype Pattern)

原形模式允許通過復(fù)制現(xiàn)有對象來創(chuàng)建新對象耳鸯,而不是通過實例化新的對象。這種模式通常用于創(chuàng)建復(fù)雜的對象膀曾,因為創(chuàng)建這些對象需要大量時間和資源县爬。

原型模式通常在以下場景中使用:

創(chuàng)建復(fù)雜對象:如果要創(chuàng)建的對象比較復(fù)雜,例如具有多個子對象或需要大量計算才能創(chuàng)建添谊,那么使用原型模式可以避免重復(fù)的計算和復(fù)雜的對象構(gòu)建過程财喳。

提高性能:使用原型模式可以提高性能,因為復(fù)制現(xiàn)有對象比創(chuàng)建新對象要斩狱。

保護對象:有時候耳高,為了保護對象的不變性,希望對象不能被修改所踊。在這種情況下祝高,使用原型模式可以確保不會修改原始對象,因為只能復(fù)制它而不是直接修改它污筷。

動態(tài)配置對象:如果要在運行時動態(tài)配置對象工闺,例如根據(jù)用戶輸入或環(huán)境變量來配置對象的屬性乍赫,那么使用原型模式可以方便地生成新對象。

它通常與工廠模式和建造者模式一起使用陆蟆,以提供更好的靈活性和可維護性雷厂。

在實際的開發(fā)中,可能會遇到需要創(chuàng)建復(fù)雜對象的場景叠殷,例如:

圖形化界面:開發(fā)一個圖形化界面改鲫,可能需要創(chuàng)建許多復(fù)雜的圖形對象,例如窗口林束、按鈕像棘、標簽、文本框等壶冒。

游戲開發(fā):可能需要創(chuàng)建許多復(fù)雜的游戲?qū)ο舐铺猓缃巧⒐治锱痔凇⒌谰叩取?/p>

數(shù)據(jù)庫訪問層:需要創(chuàng)建許多復(fù)雜的數(shù)據(jù)對象烟零,例如表格、列咸作、行等锨阿。

網(wǎng)絡(luò)通信:開發(fā)一個網(wǎng)絡(luò)應(yīng)用程序,可能需要創(chuàng)建許多復(fù)雜的網(wǎng)絡(luò)對象记罚,例如請求墅诡、響應(yīng)、協(xié)議等桐智。

在這些場景中书斜,復(fù)雜對象通常包含多個子對象或?qū)傩裕⑶铱赡苄枰獔?zhí)行多個計算或操作才能構(gòu)建酵使。使用原型模式可以避免在每次需要創(chuàng)建對象時執(zhí)行這些計算或操作荐吉,并且可以提高性能和可維護性。

例子

在 iOS 開發(fā)中口渔,創(chuàng)建一個復(fù)雜的界面可能涉及許多對象样屠,例如UIView、UILabel缺脉、UIButton等痪欲。我們可以使用原型模式來創(chuàng)建這些對象,而不需要每次都手動創(chuàng)建和配置它們攻礼。

在上面的例子中业踢,我們創(chuàng)建了一個包含多個子對象的 UIView子類 MyView,并定義了一個復(fù)制方法來實現(xiàn)對象的復(fù)制礁扮。然后知举,我們創(chuàng)建了一個原型對象 prototypeView瞬沦,并設(shè)置了它的子對象 titleLabel 和 button。最后雇锡,我們復(fù)制了原型對象逛钻,并在新對象 newView 中修改了 titleLabel 和 button 的屬性。

原型模式與工廠模式的結(jié)合使用

工廠模式用于創(chuàng)建復(fù)雜對象锰提,而原型模式則可以用于快速復(fù)制這些復(fù)雜對象曙痘。 這種結(jié)合使用可以提高對象的創(chuàng)建效率和性能

原型模式與建造者模式的結(jié)合使用

建造者模式用于創(chuàng)建復(fù)雜對象,它通過分步驟的方式來構(gòu)建對象,而原型模式可以用于快速復(fù)制已有的對象實例,使得在建造對象時更加高效。在這種結(jié)合使用的情況下倘待,建造者模式通常用于創(chuàng)建原型實例,并使用原型實例的復(fù)制方法創(chuàng)建新的對象實例。這種結(jié)合使用可以提高對象的創(chuàng)建效率和靈活性。

網(wǎng)絡(luò)請求

原型模式在網(wǎng)絡(luò)請求中也可以使用文黎,通常用于緩存請求結(jié)果以提高應(yīng)用程序的性能惹苗。在某些情況下殿较,應(yīng)用程序需要從網(wǎng)絡(luò)中獲取大量的數(shù)據(jù),并在應(yīng)用程序中多次使用相同的數(shù)據(jù)桩蓉。如果每次都從網(wǎng)絡(luò)中獲取數(shù)據(jù)淋纲,這將會降低應(yīng)用程序的性能,并且可能會因為網(wǎng)絡(luò)延遲導(dǎo)致應(yīng)用程序的響應(yīng)速度變慢院究。在這種情況下洽瞬,使用原型模式來緩存請求結(jié)果可以提高應(yīng)用程序的性能。

六业汰、建造者模式(Builder Pattern)

建造者模式(Builder Pattern)可以將對象的構(gòu)建過程與其表示分離伙窃,從而使同樣的構(gòu)建過程可以創(chuàng)建不同的表示。這種模式通常用于需要復(fù)雜對象的構(gòu)建過程样漆,并且需要將構(gòu)建過程的細節(jié)隱藏起來为障,以便于用戶只需要關(guān)心所需的結(jié)果即可。

在建造者模式中放祟,通常會定義一個Builder接口或者抽象類鳍怨,其中包含了一系列構(gòu)建復(fù)雜對象所需的方法。具體的構(gòu)建器類實現(xiàn)了Builder接口或抽象類跪妥,并根據(jù)實際情況來實現(xiàn)每個方法鞋喇,最終構(gòu)建出一個具體的產(chǎn)品對象。同時眉撵,建造者模式還定義了一個Director類侦香,用于協(xié)調(diào)Builder對象的構(gòu)建過程落塑,并且隔離客戶端和產(chǎn)品對象的直接聯(lián)系。

建造者模式通常適用于以下場景:

當創(chuàng)建一個復(fù)雜對象時鄙皇,需要分步驟地進行創(chuàng)建芜赌,且需要控制每個步驟的順序和內(nèi)容時,可以使用建造者模式伴逸。

當需要創(chuàng)建的對象具有復(fù)雜的內(nèi)部結(jié)構(gòu)時缠沈,可以使用建造者模式來隔離復(fù)雜的對象創(chuàng)建過程,從而使其更易于理解和維護错蝴。

當需要創(chuàng)建多個具有相似屬性的對象時洲愤,可以使用建造者模式來避免重復(fù)的構(gòu)造代碼,并且可以更容易地擴展和修改這些對象的構(gòu)造過程顷锰。

當需要創(chuàng)建一個不可變的對象時柬赐,可以使用建造者模式來強制其必須通過構(gòu)造器來創(chuàng)建,從而避免了對象在創(chuàng)建后被修改的可能性官紫。

例子

舉一個具體的例子肛宋,比如我們需要構(gòu)建一份簡歷,其中包括個人信息束世、教育經(jīng)歷酝陈、工作經(jīng)歷等。如果使用建造者模式毁涉,我們可以將這份簡歷的構(gòu)建過程分為多個步驟沉帮,并由具體的構(gòu)建器來負責每個步驟的實現(xiàn)。這樣做的好處是贫堰,我們可以根據(jù)不同的需求來構(gòu)建不同風格的簡歷穆壕,而不需要在客戶端代碼中重復(fù)編寫相似的代碼。

現(xiàn)在我們使用 ResumeDirector 類來調(diào)用建造者來創(chuàng)建簡歷其屏,具體代碼如下:

這個 ResumeDirector 類接受一個建造者對象喇勋,然后在 construct 方法中按照特定的順序調(diào)用建造者的方法來構(gòu)建簡歷。現(xiàn)在我們可以使用這個 ResumeDirector 來構(gòu)建簡歷:

輸出結(jié)果為:

第二種模式:結(jié)構(gòu)型模式:

結(jié)構(gòu)型模式和創(chuàng)建型模式是設(shè)計模式中的兩個主要分類偎行。

創(chuàng)建型模式關(guān)注對象的創(chuàng)建機制川背,主要解決對象的實例化過程。創(chuàng)建型模式涉及到對象的創(chuàng)建睦优、組合和表示渗常,以及隱藏對象的創(chuàng)建邏輯。

結(jié)構(gòu)型模式關(guān)注的是對象之間的組合和關(guān)聯(lián)方式汗盘,以構(gòu)建更大的結(jié)構(gòu)和功能皱碘。它們著重于類和對象之間的靜態(tài)關(guān)系,以及如何將它們組織在一起形成更大的結(jié)構(gòu)隐孽,以滿足系統(tǒng)的需求癌椿。結(jié)構(gòu)型模式可以幫助我們在保持系統(tǒng)靈活性和可擴展性的同時健蕊,提供清晰的對象組織結(jié)構(gòu)

總的來說踢俄,創(chuàng)建型模式更關(guān)注的是對象創(chuàng)建的靈活性和可維護性缩功,結(jié)構(gòu)型模式更關(guān)注的是系統(tǒng)結(jié)構(gòu)的設(shè)計和組織。

常見的結(jié)構(gòu)型模式:

1.適配器模式(Adapter Pattern)

2.橋接模式(Bridge Pattern)

3.組合模式(Composite Pattern)

4.裝飾器模式(Decorator Pattern)

5.外觀模式(Facade Pattern)

6.享元模式(Flyweight Pattern)

7.代理模式(Proxy Pattern)

這些結(jié)構(gòu)型模式都有不同的應(yīng)用場景和優(yōu)勢都办,可以根據(jù)具體的需求來選擇合適的模式來改善軟件設(shè)計的靈活性嫡锌、可維護性和可擴展性。

一琳钉、適配器模式(Adapter Pattern)

用于將一個類的接口轉(zhuǎn)換成另一個類的接口势木,以便兩個不兼容的類能夠一起工作

適配器模式可以解決在系統(tǒng)中使用已有的類歌懒,但其接口與需要的接口不匹配的情況啦桌。

使用方法:適配器繼承依賴已有的對象,實現(xiàn)想要的目標接口及皂。

繼承

適配器可以通過繼承已有的對象(舊接口)甫男,并實現(xiàn)目標接口來進行適配。通過繼承验烧,適配器獲得了舊接口的功能板驳,并且可以添加或重寫方法來實現(xiàn)目標接口的要求

在這個例子中噪窘,OldAPI是舊的接口類笋庄,它有一個legacyRequest方法效扫。NewAPI是目標接口倔监,它定義了一個newRequest方法。適配器類Adapter繼承自O(shè)ldAPI菌仁,并實現(xiàn)了NewAPI接口浩习。

通過繼承,Adapter類繼承了legacyRequest方法济丘,然后在newRequest方法中調(diào)用了legacyRequest方法來執(zhí)行舊接口的請求谱秽,并添加了適配后的新請求。

依賴

適配器也可以通過依賴已有的對象(舊接口)摹迷,并將其作為成員變量來實現(xiàn)適配疟赊。適配器可以通過委派調(diào)用已有對象的方法,并根據(jù)目標接口的要求對返回結(jié)果進行適配處理峡碉。

Adapter適配器類通過依賴舊接口類OldAPI來實現(xiàn)適配近哟。適配器類持有一個OldAPI對象的實例,并實現(xiàn)了NewAPI接口鲫寄。

在適配器的newRequest方法中吉执,適配器通過調(diào)用持有的OldAPI對象的legacyRequest方法來執(zhí)行舊接口的請求疯淫,并在之后添加了適配后的新請求的邏輯。

在客戶端代碼中戳玫,我們創(chuàng)建了適配器類Adapter的實例熙掺,并將舊接口類OldAPI的實例設(shè)置為適配器類的oldAPI屬性。然后調(diào)用適配器類的newRequest方法來發(fā)起新的請求咕宿。

無論是繼承還是依賴币绩,適配器都充當了一個中間層,通過轉(zhuǎn)換和包裝舊接口的功能府阀,使其符合目標接口的要求类浪。適配器將客戶端的調(diào)用轉(zhuǎn)換為對舊接口的調(diào)用,并對舊接口的返回結(jié)果進行適配肌似,以滿足客戶端的期望费就。

適配器模式的缺點:

增加代碼復(fù)雜性:適配器模式引入了額外的類和邏輯,增加了代碼的復(fù)雜性川队。適配器的存在可能會增加代碼的理解和維護成本力细。

運行時性能損耗:數(shù)據(jù)或方法的轉(zhuǎn)換需要額外的處理步驟。

可能會導(dǎo)致過多的適配器類:在某些情況下固额,如果系統(tǒng)中存在大量不兼容的類眠蚂,可能需要創(chuàng)建大量的適配器類來進行適配,這可能會導(dǎo)致類的數(shù)量過多斗躏,增加了系統(tǒng)的復(fù)雜性逝慧。

總體而言,適配器模式在解決接口不兼容問題提高代碼復(fù)用性方面具有明顯的優(yōu)點啄糙。然而笛臣,在設(shè)計和使用適配器時需要權(quán)衡好代碼復(fù)雜性、運行時性能以及適配器的數(shù)量隧饼,確保適配器模式的使用是合理的沈堡。

二、橋接模式(Bridge Pattern)

橋接模式用于把抽象化與實現(xiàn)化解耦燕雁,使得二者可以獨立變化诞丽。他們分離后,可以獨立地變化拐格。橋接模式通過組合而不是繼承來實現(xiàn)這種分離僧免。

在橋接模式中,抽象部分(Abstraction)和實現(xiàn)部分(Implementation)分別定義了兩個獨立的類層次結(jié)構(gòu)捏浊。抽象部分包含一個指向?qū)崿F(xiàn)部分的引用懂衩,并且通過這個引用進行交互。這樣勃痴,抽象部分就可以與不同的實現(xiàn)部分進行橋接谒所,而不會與特定的實現(xiàn)部分耦合。

橋接模式中的“橋”就是協(xié)議接口沛申,符合依賴倒轉(zhuǎn)原則和面向接口的編程劣领。

例子

在上述代碼中,我們有一個實現(xiàn)部分的接口 Implementor铁材,以及兩個具體實現(xiàn)類 ConcreteImplementorA 和 ConcreteImplementorB尖淘。抽象部分 Abstraction 持有一個 Implementor 引用,并通過它調(diào)用實現(xiàn)部分的操作著觉。

在客戶端代碼中村生,我們首先創(chuàng)建了一個具體的實現(xiàn)對象 ConcreteImplementorA,然后創(chuàng)建了抽象部分對象 Abstraction饼丘,并將實現(xiàn)對象A橋接進去趁桃。當調(diào)用抽象部分的操作[abstraction doAction] 時,實際上是通過抽象部分與具體實現(xiàn)對象A的橋接肄鸽,執(zhí)行了實現(xiàn)對象A的具體操作卫病,輸出了 "Concrete Implementor A is doing something."。

接下來典徘,我們創(chuàng)建了另一個具體的實現(xiàn)對象 ConcreteImplementorB蟀苛,并將其橋接進抽象部分對象。再次調(diào)用抽象部分的操作 [abstraction doAction] 時逮诲,由于實現(xiàn)對象B替換了實現(xiàn)對象A的橋接帜平,輸出變?yōu)榱?"Concrete Implementor B is doing something."。

橋接模式的優(yōu)點:抽象部分和實現(xiàn)部分可以獨立地擴展和變化梅鹦,它們之間的關(guān)系是通過橋接而不是繼承建立的裆甩。這種分離允許我們在不影響其他部分的情況下修改抽象部分或?qū)崿F(xiàn)部分,從而提高了系統(tǒng)的靈活性和可擴展性帘瞭。在iOS開發(fā)中淑掌,橋接模式可以應(yīng)用于以下方面:

網(wǎng)絡(luò)請求庫: 當你需要進行網(wǎng)絡(luò)請求時蒿讥,可以使用橋接模式將網(wǎng)絡(luò)請求庫與具體的網(wǎng)絡(luò)協(xié)議(如HTTP蝶念、WebSocket等)進行解耦。你可以定義一個抽象的網(wǎng)絡(luò)請求接口芋绸,并針對每種具體的網(wǎng)絡(luò)協(xié)議實現(xiàn)一個具體的網(wǎng)絡(luò)請求類媒殉。通過橋接模式,可以靈活地切換或添加新的網(wǎng)絡(luò)協(xié)議實現(xiàn)摔敛。

視圖控制器和視圖之間的橋接: 在iOS應(yīng)用中廷蓉,視圖控制器負責管理視圖的顯示和交互邏輯,而視圖負責界面的展示。你可以使用橋接模式來將視圖控制器與具體的視圖實現(xiàn)進行解耦桃犬。通過定義一個抽象的視圖接口刹悴,并針對不同的界面元素(如按鈕、標簽等)實現(xiàn)具體的視圖類攒暇,可以實現(xiàn)視圖控制器和視圖的獨立變化和組合土匀。

三、組合模式(Composite Pattern)

組合模式可以將對象組合成樹形結(jié)構(gòu)形用,以表示"整體-部分"的層次結(jié)構(gòu)就轧。組合模式使得客戶端能夠以統(tǒng)一的方式處理單個對象和組合對象,從而使得代碼更加簡潔和可擴展田度。

在組合模式中妒御,有兩種基本類型的對象:葉節(jié)點(Leaf)和組合節(jié)點(Composite)。葉節(jié)點表示樹結(jié)構(gòu)中的最小單位镇饺,它們沒有子節(jié)點乎莉。而組合節(jié)點則包含葉節(jié)點和其他組合節(jié)點,形成了樹結(jié)構(gòu)的層次關(guān)系奸笤。

例子

下面這個例子中將會演示如何使用組合模式來表示一個文件系統(tǒng)的樹形結(jié)構(gòu)梦鉴。

首先,定義一個抽象基類 FileSystemComponent揭保,它包含了共同的行為和屬性肥橙,包括名稱、添加子節(jié)點秸侣、刪除子節(jié)點存筏、獲取子節(jié)點等:

然后,定義葉節(jié)點 File 類味榛,表示文件:

接下來椭坚,定義組合節(jié)點 Directory 類,表示文件夾:

現(xiàn)在搏色,我們可以使用組合模式來構(gòu)建一個文件系統(tǒng)的樹形結(jié)構(gòu)善茎。例如:

在上面的代碼中,我們創(chuàng)建了一個文件系統(tǒng)的樹形結(jié)構(gòu)频轿。root 是根目錄垂涯,包含了 Documents 文件夾和 Pictures文件夾,以及一個名為 notes.txt 的文件航邢。Documents 文件夾中包含一個名為 readme.txt 的文件耕赘,而 Pictures文件夾中包含兩個圖片文件 photo1.jpg 和 photo2.jpg。

通過組合模式膳殷,我們可以以統(tǒng)一的方式處理文件和文件夾操骡,無論它們是葉節(jié)點還是組合節(jié)點。例如,我們可以通過遞歸遍歷整個文件系統(tǒng)來打印出所有的文件和文件夾:

調(diào)用:

通過上述代碼册招,我們可以遍歷整個文件系統(tǒng)岔激,并打印出文件和文件夾的結(jié)構(gòu)。

組合模式的優(yōu)點是是掰,它簡化了對整體和部分之間的處理鹦倚。客戶端可以一致地對待單個對象和組合對象冀惭,而不需要關(guān)心它們的具體類型震叙。這種一致性使得代碼更加靈活和可擴展,可以輕松地添加散休、刪除和修改組合節(jié)點挎扰,而無需修改客戶端代碼复斥。

在iOS開發(fā)中盔性,組合模式可以在多種場景中使用裸违。下面是一些常見的應(yīng)用場景:

視圖層次結(jié)構(gòu):在iOS中,視圖層次結(jié)構(gòu)是一個典型的樹形結(jié)構(gòu)限府。UIView類可以看作是組合模式中的組合節(jié)點夺颤,它可以包含其他UIView實例作為子視圖(葉節(jié)點)。通過使用組合模式胁勺,可以以統(tǒng)一的方式處理視圖層次結(jié)構(gòu)中的單個視圖和組合視圖世澜。

文件系統(tǒng)操作:在處理文件系統(tǒng)相關(guān)操作時,組合模式也非常有用署穗。例如寥裂,你可以使用組合模式來構(gòu)建一個文件管理器應(yīng)用程序,以便處理文件和文件夾的創(chuàng)建案疲、刪除封恰、復(fù)制等操作。組合模式使得你可以一致地對待文件和文件夾褐啡,無論是單個文件還是包含其他文件和文件夾的文件夾诺舔。

數(shù)據(jù)結(jié)構(gòu)處理:在處理具有層次結(jié)構(gòu)的數(shù)據(jù)時,組合模式可以派上用場备畦。例如低飒,你可能需要處理一個包含多級分類的數(shù)據(jù)集合,每個分類又可以包含子分類萍恕。通過使用組合模式逸嘀,可以輕松地表示和操作這種層次結(jié)構(gòu)的數(shù)據(jù)。

也即:UIView中常用的addSubview方法其實就是組合模式允粤。

通過這個方法,我們可以將一個 UIView 對象作為子視圖添加到另一個 UIView 對象中,形成視圖層次結(jié)構(gòu)类垫。

在組合模式中司光,UIView 對象可以看作是組合模式中的組合節(jié)點,它可以包含其他 UIView 對象作為子視圖(葉節(jié)點)悉患。通過使用 addSubview: 方法残家,我們可以將葉節(jié)點視圖添加到組合節(jié)點視圖中,構(gòu)建復(fù)雜的視圖層次結(jié)構(gòu)售躁。

組合模式具有以下優(yōu)點:

統(tǒng)一接口:組合模式提供了一個統(tǒng)一的接口坞淮,使得客戶端可以以相同的方式處理單個對象和組合對象。這簡化了客戶端代碼陪捷,并提高了代碼的可讀性和可維護性回窘。

簡化客戶端代碼:使用組合模式,客戶端不需要關(guān)心處理單個對象還是組合對象市袖,可以通過統(tǒng)一的接口直接操作整個對象層次結(jié)構(gòu)啡直。這樣可以簡化客戶端代碼,減少條件判斷和類型檢查的邏輯苍碟。

可擴展性:組合模式支持動態(tài)的添加酒觅、刪除和修改對象,使得對象層次結(jié)構(gòu)可以很容易地進行擴展和變化微峰。這種靈活性使得我們可以構(gòu)建復(fù)雜的對象結(jié)構(gòu)舷丹,并在不影響現(xiàn)有代碼的情況下進行修改和調(diào)整。

遞歸處理:組合模式使用遞歸的方式處理整個對象層次結(jié)構(gòu)蜓肆,可以方便地對整個層次結(jié)構(gòu)進行遍歷和操作掂榔。

組合模式也存在一些缺點:

限制類型的組合:在組合模式中,葉節(jié)點和組合節(jié)點具有相同的接口症杏,但是并不意味著所有操作對于葉節(jié)點和組合節(jié)點都是有意義的装获。有些操作可能只適用于葉節(jié)點,而有些操作可能只適用于組合節(jié)點厉颤。

對象層次結(jié)構(gòu)的復(fù)雜性:隨著對象層次結(jié)構(gòu)的增長穴豫,特別是在處理大型和復(fù)雜的層次結(jié)構(gòu)時,組合模式可能會導(dǎo)致對象層次結(jié)構(gòu)變得復(fù)雜和難以理解逼友。需要合理地劃分對象的職責和功能精肃,以避免層次結(jié)構(gòu)的過度復(fù)雜化。

可能帶來性能損失:由于組合模式涉及遞歸操作和遍歷整個對象層次結(jié)構(gòu)帜乞,可能會在一些情況下帶來一定的性能損失司抱。特別是在處理大型層次結(jié)構(gòu)時,需要仔細考慮性能問題黎烈,并根據(jù)實際情況進行優(yōu)化习柠。

總的來說匀谣,組合模式在處理對象層次結(jié)構(gòu)時提供了一種簡潔和靈活的方式,但在使用時需要注意合理劃分對象的職責和功能资溃,以及在性能方面的考慮武翎。根據(jù)具體的應(yīng)用場景和需求,權(quán)衡利弊后選擇是否 使用組合模式溶锭。

四宝恶、裝飾器模式(Decorator Pattern)

裝飾器模式最大的特點就是在不改變現(xiàn)有對象結(jié)構(gòu)的情況下,動態(tài)地向?qū)ο?b>添加新的行為或功能趴捅。

裝飾器模式通過將對象包裝在一個裝飾器對象中垫毙,來擴展對象的功能。

在iOS開發(fā)中拱绑,裝飾器模式常常用于以下情況:

動態(tài)擴展對象的功能:當我們需要在不修改現(xiàn)有代碼的情況下综芥,為一個對象添加額外的功能時,可以使用裝飾器模式欺栗。這樣可以避免修改原有代碼毫痕,同時實現(xiàn)功能的靈活組合。

對象功能的組合:當一個對象可能有多個功能組合的情況下迟几,裝飾器模式可以讓我們通過不同的裝飾器進行功能的組合消请。

裝飾器模式也可以與其他設(shè)計模式結(jié)合使用,例如結(jié)合工廠模式來創(chuàng)建裝飾器對象类腮。

例子

首先臊泰,我們定義一個抽象的形狀接口 Shape:

然后,我們創(chuàng)建具體的形狀類蚜枢,如矩形和圓形:

接下來缸逃,我們創(chuàng)建具體的裝飾器類 ColorDecorator 和 BorderDecorator,它們實現(xiàn)了 Shape 接口厂抽,并在 draw 方法中添加了顏色和邊框的繪制:

接下來需频,我們定義一個裝飾器工廠類 ShapeDecoratorFactory,用于創(chuàng)建裝飾器對象:

接下來筷凤,我們可以使用裝飾器工廠類 ShapeDecoratorFactory 來創(chuàng)建裝飾后的形狀對象昭殉。以下是一個示例的使用代碼:

裝飾器模式具有以下優(yōu)點:

動態(tài)擴展功能:裝飾器模式允許在不修改現(xiàn)有代碼的情況下,動態(tài)地為對象添加額外的功能藐守。通過裝飾器模式挪丢,可以在運行時對對象進行靈活的功能組合,實現(xiàn)功能的動態(tài)擴展卢厂。

遵循開放封閉原則:裝飾器模式可以遵循開放封閉原則乾蓬,即對擴展開放,對修改封閉慎恒。通過裝飾器模式任内,可以通過添加裝飾器來擴展對象的功能撵渡,而無需修改原有對象的代碼。

避免繼承的復(fù)雜性:裝飾器模式通過組合和委托的方式族奢,避免了使用大量的子類來實現(xiàn)功能的擴展姥闭。相比于繼承丹鸿,裝飾器模式更加靈活越走,并且可以在運行時動態(tài)地組合功能。

單一職責原則:裝飾器模式可以將功能的細粒度分離靠欢,每個裝飾器類只關(guān)注特定的功能擴展廊敌,使得每個類都具有單一職責。

然而门怪,裝飾器模式也存在一些缺點:

增加復(fù)雜性:使用裝飾器模式會增加額外的類和對象骡澈,導(dǎo)致代碼結(jié)構(gòu)變得更加復(fù)雜,理解和維護成本增加掷空。

裝飾器順序依賴:如果裝飾器的順序不正確肋殴,可能會影響功能的正確執(zhí)行。特別是當多個裝飾器共同修改同一個方法時坦弟,裝飾器的順序非常重要护锤。

不適合大量裝飾器的情況:如果需要使用大量的裝飾器來裝飾對象,會導(dǎo)致裝飾器的層級嵌套過深酿傍,代碼變得復(fù)雜且難以維護烙懦。

因此,如果需要動態(tài)擴展對象的功能且保持代碼的靈活性赤炒,裝飾器模式是一種有效的設(shè)計模式選擇氯析。

五、外觀模式(Facade Pattern)

外觀模式提供了一個簡單而統(tǒng)一的接口莺褒,用于訪問復(fù)雜系統(tǒng)中的一組接口掩缓。

外觀模式隱藏了系統(tǒng)的復(fù)雜性,并為客戶端提供了一個更簡單和更直接的訪問方式遵岩。它可以將一個復(fù)雜的子系統(tǒng)封裝起來你辣,客戶端只需要通過與外觀對象進行交互,而無需直接與子系統(tǒng)中的各個對象進行交互旷余。

在iOS開發(fā)中绢记,外觀模式常用于簡化復(fù)雜的系統(tǒng)或框架,并提供一個更簡單的接口供客戶端使用正卧。

也就是說蠢熄,在使用第三方庫的應(yīng)用中,對第三方庫進行封裝炉旷,便于客戶端的使用签孔,就是外觀模式的一種體現(xiàn)叉讥。

外觀模式有以下優(yōu)點:

簡化接口:外觀模式提供了一個簡化的接口,隱藏了底層系統(tǒng)的復(fù)雜性饥追,使得客戶端更容易使用和理解系統(tǒng)功能图仓。

解耦合:外觀模式將客戶端與底層系統(tǒng)解耦,客戶端只需要通過外觀類與系統(tǒng)進行交互但绕,而不需要直接與系統(tǒng)的各個子組件進行交互救崔。

提高靈活性:通過外觀類作為中間層,可以靈活地修改底層系統(tǒng)的實現(xiàn)細節(jié)捏顺,而不影響客戶端的代碼六孵。

提高可維護性:外觀模式將底層系統(tǒng)的復(fù)雜性封裝在一個類中,使得系統(tǒng)結(jié)構(gòu)更加清晰幅骄,易于理解和維護劫窒。

外觀模式也有一些缺點:

不符合開閉原則當?shù)讓酉到y(tǒng)發(fā)生變化時,可能需要修改外觀類的代碼拆座,這違反了對修改關(guān)閉的原則主巍。

可能引入性能問題:外觀模式的封裝會增加一層額外的間接調(diào)用,可能會對系統(tǒng)的性能產(chǎn)生一定影響挪凑。

可能導(dǎo)致過度設(shè)計:過度使用外觀模式可能導(dǎo)致系統(tǒng)結(jié)構(gòu)過于復(fù)雜孕索,增加不必要的代碼復(fù)雜性和維護成本。

六岖赋、享元模式(Flyweight Pattern)

享元模式旨在通過共享對象減少內(nèi)存使用和提高性能檬果。它適用于存在大量相似對象的情況,通過共享這些對象的公共部分來減少內(nèi)存消耗唐断。

在享元模式中选脊,對象分為兩種類型:內(nèi)部狀態(tài)(Intrinsic State)和外部狀態(tài)(Extrinsic State)。內(nèi)部狀態(tài)是可以被共享的脸甘,它包含對象的固有屬性恳啥,不會因外部環(huán)境的改變而改變。外部狀態(tài)是不可共享的丹诀,它取決于對象被使用的上下文钝的。

在iOS開發(fā)中,享元模式可以應(yīng)用于以下場景:

視圖復(fù)用:在使用UITableView或UICollectionView等可重用視圖的情況下铆遭,可以使用享元模式來共享可重用視圖的實例。這樣可以避免頻繁地創(chuàng)建和銷毀視圖對象矢劲,提高滾動性能和響應(yīng)速度隘击。

圖像緩存:在需要頻繁加載和顯示大量圖像的應(yīng)用中集嵌,可以使用享元模式來共享已加載的圖像實例。這樣可以避免重復(fù)加載相同的圖像欺税,減少內(nèi)存消耗侈沪,并提高性能揭璃。

字符串常量池:在應(yīng)用中使用的字符串常量(例如錯誤提示、網(wǎng)絡(luò)請求URL等)可以被視為享元對象亭罪。通過共享這些字符串常量的實例瘦馍,可以節(jié)省內(nèi)存并提高字符串比較的效率。

總之应役,享元模式在iOS開發(fā)中可以用于任何需要共享大量相似對象降低內(nèi)存消耗的場景情组。

圖像緩存

當需要頻繁加載和顯示大量圖像的應(yīng)用中,使用享元模式可以有效地進行圖像緩存箩祥,避免重復(fù)加載相同的圖像院崇,減少內(nèi)存消耗,并提高性能袍祖。

享元模式具有以下優(yōu)點:

減少內(nèi)存消耗:通過共享對象實例底瓣,可以大大減少系統(tǒng)中相似對象的數(shù)量,從而降低內(nèi)存消耗蕉陋。共享的對象可以被多個客戶端共同使用捐凭,避免了創(chuàng)建大量相似對象的開銷。

提高性能:由于減少了對象的數(shù)量凳鬓,享元模式可以提高系統(tǒng)的性能茁肠。重復(fù)使用共享對象可以避免頻繁的對象創(chuàng)建和銷毀操作,從而減少了系統(tǒng)的開銷缩举。

狀態(tài)外部化:享元模式將對象的內(nèi)部狀態(tài)和外部狀態(tài)分離垦梆。內(nèi)部狀態(tài)是可以共享的,而外部狀態(tài)是變化的仅孩,可以根據(jù)需要傳遞給享元對象托猩。這種狀態(tài)的外部化可以簡化對象的邏輯,使對象更易于使用和維護杠氢。

提高可維護性和可擴展性:通過將對象的狀態(tài)外部化站刑,享元模式使得對象的邏輯更加清晰和簡潔。這樣可以提高代碼的可維護性和可擴展性鼻百,使系統(tǒng)更容易理解和修改绞旅。

然而,享元模式也有一些限制和缺點:

共享對象的狀態(tài)必須是可共享的:享元模式要求對象的內(nèi)部狀態(tài)可以被共享温艇,而外部狀態(tài)可以在使用時傳遞因悲。如果對象的狀態(tài)不可共享,那么無法使用享元模式來實現(xiàn)對象的共享和復(fù)用勺爱。

增加了系統(tǒng)的復(fù)雜性:享元模式將對象分為內(nèi)部狀態(tài)和外部狀態(tài)晃琳,并且需要額外的邏輯來管理共享對象的創(chuàng)建和訪問。這樣會增加系統(tǒng)的復(fù)雜性,需要仔細考慮對象的狀態(tài)和共享機制的設(shè)計卫旱。

可能導(dǎo)致線程安全問題:如果多個線程同時訪問和修改共享對象的狀態(tài)人灼,可能會導(dǎo)致線程安全問題。在使用享元模式時顾翼,需要注意對共享對象的狀態(tài)進行正確的同步和管理投放,以避免并發(fā)訪問問題

綜上所述适贸,享元模式適用于需要共享大量相似對象灸芳,并且可以提供內(nèi)存和性能優(yōu)化的場景。

七拜姿、代理模式(Proxy Pattern)

代理模式通過創(chuàng)建一個代理對象來控制對另一個對象的訪問烙样。

代理對象充當原始對象的中間人,客戶端通過代理對象與原始對象進行交互蕊肥,代理對象可以在不修改原始對象的情況下增加額外的功能谒获。

代理模式的主要目的是實現(xiàn)對對象的間接訪問,以提供更靈活的控制和擴展晴埂。代理模式常見的應(yīng)用場景包括:

遠程代理:允許通過網(wǎng)絡(luò)訪問遠程對象究反,隱藏了底層的復(fù)雜性

虛擬代理:用于懶加載對象儒洛,只有在需要時才會創(chuàng)建真實對象。

安全代理:控制對對象的訪問權(quán)限狼速。

智能代理:在訪問對象時執(zhí)行額外的邏輯琅锻,如緩存、日志記錄等向胡。

例子

假設(shè)我們有一個下載器對象(Downloader)負責從互聯(lián)網(wǎng)上下載文件∧张睿現(xiàn)在我們希望在每次下載前后記錄下載日志。我們可以使用代理模式來實現(xiàn):

在上述示例中僵芹,Downloader是一個協(xié)議处硬,定義了下載文件的方法downloadFile:。RealDownloader是實際執(zhí)行下載操作的對象拇派,它實現(xiàn)了Downloader協(xié)議稠茂。DownloaderProxy是代理對象稻艰,也實現(xiàn)了Downloader協(xié)議。

當客戶端調(diào)用代理對象的downloadFile:方法時,代理對象在下載前后分別輸出日志信息摇邦,并將實際的下載操作委托給RealDownloader對象執(zhí)行。

代理模式有以下優(yōu)點:

隔離客戶端和真實對象:代理模式通過代理對象將客戶端與真實對象隔離開來常侦,客戶端不直接與真實對象交互星爪,而是通過代理對象進行間接訪問。這樣可以減少客戶端與真實對象之間的耦合,提高系統(tǒng)的靈活性和可維護性惫谤。

控制對真實對象的訪問:代理對象可以在訪問真實對象之前或之后執(zhí)行額外的操作壁顶,例如權(quán)限控制、緩存溜歪、延遲加載等博助。這樣可以對真實對象的訪問進行控制和管理,增加了系統(tǒng)的安全性和可控性痹愚。

提供額外的功能:代理對象可以在不修改真實對象的情況下富岳,擴展或增強其功能。例如拯腮,代理對象可以添加日志記錄窖式、性能統(tǒng)計、異常處理等功能动壤,從而為客戶端提供更多的服務(wù)萝喘。

代理模式也有一些缺點:

增加了系統(tǒng)復(fù)雜性:引入代理對象會增加系統(tǒng)中的類和對象數(shù)量,導(dǎo)致系統(tǒng)的復(fù)雜性增加琼懊。過多的代理對象可能會使代碼結(jié)構(gòu)變得復(fù)雜阁簸,難以理解和維護。

增加了請求的處理時間:由于代理模式引入了額外的對象哼丈,每個請求都需要經(jīng)過代理對象的處理启妹,可能會增加一定的處理時間。

可能降低直接訪問的效率:由于代理模式是通過間接訪問實現(xiàn)的醉旦,所以在直接訪問真實對象時可能會降低一些效率饶米。

第三種模式:行為型模式:

行為型模式和結(jié)構(gòu)型模式、創(chuàng)建型模式一樣车胡,是設(shè)計模式中的主要分類檬输。

創(chuàng)建型模式更關(guān)注的是對象創(chuàng)建的靈活性和可維護性,結(jié)構(gòu)型模式更關(guān)注的是系統(tǒng)結(jié)構(gòu)的設(shè)計和組織匈棘。

行為型模式(Behavioral Patterns)關(guān)注的是對象之間的通信和交互方式丧慈,以實現(xiàn)特定的行為和責任分配

雖然行為型模式主卫、結(jié)構(gòu)型模式和創(chuàng)建型模式關(guān)注的方面不同逃默,但它們之間也存在聯(lián)系和互相影響。在實際應(yīng)用中队秩,這些模式往往會結(jié)合使用笑旺,以達到更好的設(shè)計和架構(gòu)。例如馍资,我們可以使用創(chuàng)建型模式創(chuàng)建對象筒主,并使用結(jié)構(gòu)型模式組織和管理這些對象关噪,最后使用行為型模式定義對象之間的交互方式

常見的行為型模式:

1.責任鏈模式(Chain of Responsibility Pattern)

2.觀察者模式(Observer Pattern)

3.策略模式(Strategy Pattern)

4.模板方法模式(Template Method Pattern)

5.命令模式(Command Pattern)

6.解釋器模式(Interpreter Pattern)

7.迭代器模式(Iterator Pattern)

8.中介者模式(Mediator Pattern)

9.備忘錄模式(Memento Pattern)

10.狀態(tài)模式(State Pattern)

11.訪問者模式(Visitor Pattern)

在iOS 的實際開發(fā)中乌妙,責任鏈模式使兔,觀察者模式,策略模式藤韵,模板方法模式 這四種模式比較常用虐沥。

一、責任鏈模式(Chain of Responsibility Pattern)

責任鏈模式將請求沿著處理鏈傳遞泽艘,直到有一個處理者能夠處理該請求欲险。在責任鏈模式中,每個處理者都有一個對下一個處理者的引用匹涮,形成一個鏈條天试。

這種模式的主要目的是解耦發(fā)送者和接收者之間的關(guān)系發(fā)送者不需要知道具體是哪個接收者會處理請求然低,而接收者也不需要知道請求的發(fā)送者是誰喜每。 通過這種方式,責任鏈模式可以靈活地添加雳攘、修改或者刪除處理者带兜,而不會對系統(tǒng)的其他部分產(chǎn)生影響。

責任鏈模式是在iOS 的實際開發(fā)中比較常用的模式:常用于處理事件或請求的傳遞吨灭。不同的對象可以按照一定的順序處理事件刚照,直到有對象能夠處理該事件為止。

例子

使用:

在這個示例中沃于,抽象處理者(Handler)定義了一個處理請求的方法 handleRequest:涩咖,并持有一個對下一個處理者的引用 nextHandler。具體的處理者(ConcreteHandlerA繁莹、ConcreteHandlerB和ConcreteHandlerC)繼承自抽象處理者,并實現(xiàn)了自己的處理邏輯特幔。

客戶端代碼創(chuàng)建了具體處理者的實例咨演,并通過設(shè)置 nextHandler 屬性將它們鏈接在一起形成責任鏈。當一個請求被發(fā)送給第一個處理者時蚯斯,它會首先嘗試處理請求薄风,如果不滿足處理條件,則將請求傳遞給下一個處理者拍嵌,直到有一個處理者能夠處理請求或者到達鏈的末尾遭赂。

在上述代碼中,客戶端發(fā)送了三個請求:5横辆、15和25撇他。根據(jù)具體處理者的處理條件,請求被傳遞到了不同的處理者進行處理。輸出結(jié)果如下:

在iOS 開發(fā)中困肩,責任鏈模式一般應(yīng)用于以下場景:

事件處理:當一個事件需要經(jīng)過多個對象進行處理時划纽,可以使用責任鏈模式。例如锌畸,iOS中的事件傳遞機制就可以看作是責任鏈模式的應(yīng)用勇劣。事件首先被傳遞給視圖層次結(jié)構(gòu)中的頂層視圖,然后逐級向下傳遞潭枣,直到找到能夠處理該事件的視圖比默。

錯誤處理:當在應(yīng)用中發(fā)生錯誤時,可以使用責任鏈模式來處理錯誤盆犁。每個處理者可以根據(jù)錯誤的類型命咐、嚴重程度等條件來決定是否能夠處理該錯誤。如果一個處理者無法處理該錯誤蚣抗,將錯誤傳遞給下一個處理者侈百,直到找到能夠處理的處理者或者到達鏈的末尾。

請求過濾和驗證:在網(wǎng)絡(luò)請求或者數(shù)據(jù)處理中翰铡,可以使用責任鏈模式對請求進行過濾和驗證钝域。每個處理者可以根據(jù)請求的特定條件進行過濾和驗證操作,例如驗證請求的合法性锭魔、驗證用戶權(quán)限等例证。

消息傳遞和通知處理:當需要將消息或者通知傳遞給多個對象時,可以使用責任鏈模式迷捧。每個處理者可以根據(jù)消息的內(nèi)容或者類型來決定是否處理該消息织咧,并進行相應(yīng)的操作。

責任鏈模式具有以下優(yōu)點:

解耦:責任鏈模式將發(fā)送者和接收者解耦漠秋,發(fā)送者不需要知道具體的接收者笙蒙,而接收者也不需要知道請求的發(fā)送者,使系統(tǒng)的各個部分之間的耦合度降低庆锦。

靈活性捅位,可擴展性:責任鏈模式允許動態(tài)地添加、修改或刪除處理者搂抒,可以根據(jù)實際需求靈活地調(diào)整處理鏈的結(jié)構(gòu)和順序艇搀,而不會影響其他部分的代碼。

可維護性每個處理者只關(guān)注自己的職責求晶,使得代碼更加模塊化和可維護焰雕。

責任鏈模式也有一些缺點

請求的處理不保證被接收:由于每個處理者都有可能處理或者傳遞請求,因此不能保證請求一定會被處理或者接收者會被找到芳杏。如果責任鏈沒有被正確地構(gòu)建或者配置矩屁,請求可能會被忽略辟宗。

性能影響:在責任鏈中,請求需要經(jīng)過多個處理者的依次處理档插,可能會導(dǎo)致處理鏈較長慢蜓,影響性能。

可能導(dǎo)致系統(tǒng)變復(fù)雜:如果責任鏈的設(shè)計不當或者鏈條過長郭膛,可能會導(dǎo)致代碼變得復(fù)雜晨抡,降低代碼的可讀性和可維護性。

綜上所述则剃,責任鏈模式在解耦耘柱、靈活性和可擴展性方面具有優(yōu)點,但需要注意處理順序棍现、性能和代碼復(fù)雜性等問題调煎。

二、觀察者模式(Observer Pattern)

觀察者模式用于對象之間的一對多依賴關(guān)系己肮。在該模式中士袄,一個對象(稱為主題或可觀察者)維護一系列觀察者對象,使得當主題狀態(tài)發(fā)生變化時谎僻,所有觀察者都會自動收到通知并進行相應(yīng)的更新娄柳。

而在iOS開發(fā)中,通過使用KVO(Key-Value Observing)機制NotificationCenter 實現(xiàn)觀察者模式艘绍,可以實現(xiàn)對象之間的松耦合通信赤拒。

例子

在iOS 開發(fā)中,觀察者模式經(jīng)常使用NotificationCenter 來實現(xiàn)事件和數(shù)據(jù)的通知機制诱鞠。NotificationCenter 是一個全局的通知中心挎挖,允許不同的對象發(fā)布和接收通知。

假設(shè)我們有一個需求航夺,當用戶完成登錄操作后蕉朵,需要通知其他模塊進行相應(yīng)的更新。我們可以使用觀察者模式來實現(xiàn)這個功能阳掐。

首先墓造,在登錄完成后,我們會發(fā)送一個通知:

然后锚烦,在其他模塊中,我們可以注冊對該通知的觀察帝雇,以便在收到通知時執(zhí)行相應(yīng)的操作:

這種方式在iOS 開發(fā)中廣泛應(yīng)用涮俄,比如在數(shù)據(jù)更新時發(fā)送通知,讓相關(guān)的UI 模塊進行刷新尸闸,或者在應(yīng)用程序狀態(tài)發(fā)生變化時發(fā)送通知彻亲,讓其他模塊作出相應(yīng)的處理孕锄。觀察者模式的使用可以大大簡化不同模塊之間的交互和通信,提高代碼的可維護性和可擴展性苞尝。

三畸肆、策略模式(Strategy Pattern)

策略模式通過定義不同的策略對象,并將其封裝在具體的類中宙址,可以實現(xiàn)在運行時動態(tài)地選擇不同的算法或行為轴脐。

策略模式將算法獨立于使用它的客戶端進行封裝,使得算法可以獨立于客戶端的變化而變化抡砂。這種模式通過定義一系列可互換的算法族大咱,并將每個算法封裝起來注益,使它們可以相互替換碴巾。

例子

算法選擇:當需要根據(jù)不同的條件或用戶輸入選擇不同的算法時,可以使用策略模式丑搔。例如厦瓢,對于一個計算器應(yīng)用程序,可以根據(jù)用戶選擇的運算符使用不同的算法來執(zhí)行計算:

首先啤月,我們定義一個策略接口(Strategy)來聲明所有具體策略類都需要實現(xiàn)的方法:

然后煮仇,我們實現(xiàn)幾個具體的策略類,它們實現(xiàn)了策略接口的方法:

接下來顽冶,我們定義一個上下文類(Calculator)欺抗,它包含一個指向策略接口的引用,并提供一個方法供客戶端設(shè)置具體的策略:

最后强重,使用:

運行上述代碼绞呈,將會輸出以下結(jié)果:

通過使用策略模式,我們可以根據(jù)用戶選擇的不同運算符间景,動態(tài)地切換不同的策略佃声,從而實現(xiàn)不同的計算操作。這種模式使得算法的變化獨立于客戶端倘要,并且提高了代碼的靈活性和可維護性圾亏。

策略模式具有以下優(yōu)點:

提供了更好的代碼組織和結(jié)構(gòu):策略模式將每個具體策略類封裝在單獨的類中,使得代碼結(jié)構(gòu)清晰封拧、可讀性強志鹃。它將算法的實現(xiàn)與使用算法的客戶端代碼分離,降低了耦合性泽西,使代碼更易于維護和擴展曹铃。

提供了更高的靈活性和可擴展性:策略模式使得可以在運行時動態(tài)地切換不同的策略,而不需要修改客戶端代碼捧杉。新的策略類可以很容易地添加到系統(tǒng)中陕见,從而增加了系統(tǒng)的靈活性和可擴展性秘血。

使算法獨立于客戶端:策略模式將算法封裝在策略類中,使得算法可以獨立于客戶端進行變化评甜』伊福客戶端只需要知道如何選擇和使用不同的策略,而無需了解具體策略的實現(xiàn)細節(jié)忍坷,提高了代碼的抽象程度和可理解性粘舟。

促進了代碼復(fù)用:通過定義通用的策略接口和多個具體策略類,可以促進代碼的復(fù)用承匣。不同的客戶端可以共享相同的策略類蓖乘,避免了代碼的重復(fù)編寫。

然而韧骗,策略模式也存在一些缺點:

增加了類的數(shù)量:引入策略模式會增加類的數(shù)量嘉抒,特別是當策略較多時,可能會導(dǎo)致類的爆炸性增長袍暴,增加了代碼的復(fù)雜性些侍。

客戶端需要了解不同的策略:雖然客戶端代碼與具體策略的實現(xiàn)分離,但客戶端仍然需要了解不同策略的存在和選擇政模。

策略的選擇和切換開銷:在運行時選擇不同的策略會引入一定的開銷岗宣。如果策略的選擇頻繁發(fā)生變化,可能會影響系統(tǒng)的性能淋样。

四耗式、模板方法模式(Template Method Pattern)

模板方法模式定義了一個操作中的算法的骨架將一些步驟延遲到子類中實現(xiàn)趁猴。模板方法允許子類在不改變算法結(jié)構(gòu)的情況下重新定義算法的某些步驟刊咳。

在iOS開發(fā)中,通過定義一個抽象類或協(xié)議儡司,并在其中定義一個模板方法娱挨,允許子類或遵循者實現(xiàn)特定的步驟,從而實現(xiàn)代碼復(fù)用和統(tǒng)一的算法骨架捕犬。

例子

使用:

在上述示例中跷坝,AbstractClass是基類,定義了模板方法templateMethod和兩個抽象方法primitiveOperation1和primitiveOperation2碉碉。子類ConcreteClass1和ConcreteClass2繼承了AbstractClass柴钻,并實現(xiàn)了抽象方法。在使用示例中垢粮,我們可以看到不同子類的具體實現(xiàn)步驟在模板方法中被調(diào)用顿颅。這樣,模板方法提供了算法的骨架,而具體實現(xiàn)由子類完成粱腻。

在iOS開發(fā)中,模板方法模式常常用于以下場景:

UIViewController的生命周期方法:在iOS開發(fā)中斩跌,UIViewController 是一個常用的基類绍些,用于管理視圖控制器的生命周期和視圖的顯示。UIViewController 提供了一系列生命周期方法(例如viewDidLoad耀鸦、viewWillAppear柬批、viewWillDisappear等),開發(fā)者可以重寫這些方法以添加自定義邏輯袖订。這里的生命周期方法可以看作是模板方法氮帐,定義了視圖控制器的整體行為骨架,而具體的實現(xiàn)可以由子類重寫洛姑。

UITableView和UICollectionView的數(shù)據(jù)源方法:UITableView 和UICollectionView 是iOS 開發(fā)中常用的用于顯示列表和網(wǎng)格的視圖控件上沐。它們使用數(shù)據(jù)源協(xié)議(UITableViewDataSource和UICollectionViewDataSource)來提供數(shù)據(jù)和配置單元格。這些數(shù)據(jù)源方法(例如numberOfSectionsInTableView楞艾、numberOfRowsInSection参咙、cellForRowAtIndexPath等)可以看作是模板方法,定義了列表或網(wǎng)格的整體結(jié)構(gòu)硫眯,而具體的實現(xiàn)由數(shù)據(jù)源對象提供蕴侧。

在這些場景中,模板方法模式能夠提供一個框架或者約定两入,使得基類或協(xié)議定義了整體行為的骨架净宵,而具體的實現(xiàn)可以由子類或?qū)ο髞硖峁_@種模式可以提高代碼的可重用性和可維護性裹纳,同時也能夠提供一致的編程接口和約束择葡,方便開發(fā)者進行擴展和定制。

模板方法模式也有一些缺點:

限制了部分自由度:模板方法模式在定義算法骨架時痊夭,將一些步驟固定下來刁岸,子類只能重寫或擴展指定的方法。

增加了類的個數(shù):使用模板方法模式需要定義基類和多個子類她我,這樣會增加類的個數(shù)和代碼量虹曙。如果算法的變化較小或者只有少數(shù)幾個子類需要不同的實現(xiàn),使用模板方法模式可能會顯得過于繁瑣番舆。

難以控制子類的行為:在模板方法模式中冬骚,子類可以通過重寫方法來實現(xiàn)特定步驟的定制,這也意味著子類可能會對算法的整體行為產(chǎn)生影響咒钟。

五糙臼、命令模式(Command Pattern)

命令模式用于將請求(命令)封裝成一個對象,從而允許根據(jù)不同的請求參數(shù)來參數(shù)化客戶端對象禾怠。通過使用命令模式返奉,可以將方法調(diào)用贝搁、請求或操作封裝到單個對象中,使得我們可以將這些命令隊列芽偏、記錄日志雷逆、撤銷操作或進行重做等。

在命令模式中污尉,有四個核心組件

命令(Command):命令對象封裝了對特定操作的請求膀哲。它通常包含執(zhí)行操作的方法。

發(fā)送者(Invoker):發(fā)送者是一個對象被碗,它知道如何觸發(fā)命令來執(zhí)行特定的操作某宪。它將命令對象與接收者對象解耦

接收者(Receiver):接收者是實際執(zhí)行操作的對象锐朴。命令模式通過將命令與接收者分離兴喂,使得可以獨立地改變接收者或命令,而不需要修改發(fā)送者包颁。

客戶端(Client):客戶端創(chuàng)建具體的命令對象并設(shè)置其接收者瞻想。

例子

首先,我們創(chuàng)建一個命令接口 Command娩嚼,其中包含一個執(zhí)行方法 execute:

接下來蘑险,我們實現(xiàn)接收者類 Receiver,其中包含執(zhí)行實際操作的方法:

然后岳悟,我們實現(xiàn)具體的命令類 ConcreteCommand佃迄,它遵循命令接口,并將操作請求委托給接收者對象:

最后贵少,我們實現(xiàn)發(fā)送者類 Invoker呵俏,它接受命令對象并調(diào)用其執(zhí)行方法:

使用:

這個例子中,命令模式將一個特定的操作(performAction)封裝在一個命令對象中滔灶。發(fā)送者(Invoker)通過持有命令對象普碎,可以觸發(fā)命令的執(zhí)行,而無需直接與接收者(Receiver)進行交互录平。這種解耦允許我們靈活地替換命令或接收者麻车,以滿足不同的需求。

在iOS開發(fā)中斗这,命令模式可以在以下幾個常見場景中使用:

撤銷和重做操作:命令模式可以用于實現(xiàn)撤銷和重做操作动猬。通過將操作封裝成命令對象,可以將每個操作保存在一個歷史記錄中表箭,并在需要時按照順序執(zhí)行或撤銷赁咙。這在圖形編輯器、文本編輯器等應(yīng)用程序中非常有用。

動作菜單和工具欄:命令模式可以用于實現(xiàn)動作菜單和工具欄彼水。每個菜單項或工具欄按鈕可以關(guān)聯(lián)一個命令對象崔拥,并在觸發(fā)時執(zhí)行相應(yīng)的命令。這種方式使得用戶界面的動作和操作與實際的命令對象解耦猿涨,使得用戶界面更加靈活和可擴展握童。

異步任務(wù)隊列:命令模式可以用于管理異步任務(wù)隊列。每個命令對象可以代表一個需要執(zhí)行的異步任務(wù)叛赚,將任務(wù)的執(zhí)行封裝在命令對象中。通過使用命令模式稽揭,可以實現(xiàn)任務(wù)隊列的管理俺附、優(yōu)先級控制、任務(wù)取消等功能溪掀。

異步任務(wù)隊列

命令模式管理異步任務(wù)隊列事镣,實現(xiàn)添加、刪除和執(zhí)行任務(wù)揪胃,可以實現(xiàn)任務(wù)的優(yōu)先級控制璃哟,也可以支持任務(wù)的暫停。

六喊递、解釋器模式(Interpreter Pattern)

解釋器模式(Interpreter Pattern)用于定義一種語言的文法規(guī)則随闪,并且解釋和執(zhí)行該語言中的表達式。該模式將一個問題領(lǐng)域劃分為一組類骚勘,每個類代表語言中的一個文法規(guī)則铐伴,而解釋器則使用這些類來解釋語言中的表達式。

解釋器模式主要由以下幾個角色組成:

抽象表達式(Abstract Expression):定義了一個抽象的解釋方法 interpret俏讹,所有具體表達式都要實現(xiàn)該方法当宴。

終結(jié)符表達式(Terminal Expression):實現(xiàn)了抽象表達式的解釋方法,它代表語言中的終結(jié)符泽疆,不能再進行進一步解釋户矢。

非終結(jié)符表達式(Nonterminal Expression):實現(xiàn)了抽象表達式的解釋方法,它代表語言中的非終結(jié)符殉疼,可以繼續(xù)進行進一步解釋梯浪。

上下文(Context):包含解釋器解釋的全局信息。

客戶端(Client):創(chuàng)建并配置表達式的解釋器株依,并調(diào)用解釋方法解析語言中的表達式驱证。

(事實上,解釋器模式在iOS 開發(fā)中比較少用)

例子

假設(shè)我們有一個簡單的算術(shù)表達式語言恋腕,可以計算加法和減法:

使用:

在上面的示例中抹锄,我們定義了抽象表達式 Expression,并實現(xiàn)了終結(jié)符表達式 NumberExpression 和非終結(jié)符表達式 AdditionExpression、SubtractionExpression伙单。上下文 Context 包含了表達式解釋所需的全局信息获高。在客戶端代碼中,我們創(chuàng)建了一個算術(shù)表達式吻育,并使用上下文中的變量進行解釋和計算念秧,最后輸出計算結(jié)果。

但是也可以看到布疼,類型檢查和類型轉(zhuǎn)換非常繁瑣摊趾,如果使用Swift 這樣的語言,可能會得到改善游两,但事實上砾层,在iOS 實際開發(fā)中,解釋器模式確實比較少用到贱案,它通常在需要構(gòu)建一種特定語言的解釋器或者需要解析復(fù)雜的表達式時使用肛炮。

七、迭代器模式(Iterator Pattern)

迭代器模式提供了一種訪問集合對象元素的方法宝踪,而無需暴露集合的內(nèi)部表示侨糟。通過使用迭代器模式,可以在不暴露集合內(nèi)部結(jié)構(gòu)的情況下瘩燥,按順序訪問集合中的元素秕重。

通常,可以使用迭代器模式來遍歷集合對象(如數(shù)組颤芬、字典等)悲幅。

例子

使用:

在上面的代碼中,我們首先定義了迭代器接口(Iterator)和集合接口(Aggregate)站蝠。然后汰具,我們實現(xiàn)了具體的迭代器類(ConcreteIterator),它維護了一個集合對象和當前元素的索引菱魔,實現(xiàn)了迭代器接口中的方法留荔。接著,我們實現(xiàn)了具體的集合類(ConcreteAggregate)澜倦,它實現(xiàn)了集合接口聚蝶,并在createIterator方法中返回一個具體迭代器對象。最后藻治,我們使用迭代器來遍歷集合對象的元素碘勉。

使用迭代器模式的好處是,客戶端代碼可以通過統(tǒng)一的迭代器接口來訪問不同類型的集合對象桩卵,而無需關(guān)心集合內(nèi)部的實現(xiàn)細節(jié)验靡。這樣可以使代碼更加靈活倍宾、可擴展,并且符合面向?qū)ο蟮脑O(shè)計原則胜嗓。

八高职、中介者模式(Mediator Pattern)

中介者模式通過封裝一系列對象之間的交互,將對象之間的通信轉(zhuǎn)變?yōu)橥ㄟ^中介者進行的集中式通信辞州。中介者模式的目標是減少對象之間的直接耦合怔锌,通過引入一個中介者對象,使得對象之間的交互更加靈活变过、可維護和可擴展埃元。

在中介者模式中,各個對象不再直接相互通信媚狰,而是通過中介者進行通信亚情。當一個對象發(fā)生改變時,它不需要知道具體需要通知哪些對象哈雏,而是將消息發(fā)送給中介者,由中介者來處理通知其他相關(guān)對象衫生。這樣裳瘪,對象之間的耦合度降低,它們只需要和中介者進行通信罪针,而不需要了解其他對象的具體細節(jié)彭羹。

例子

現(xiàn)在有兩個同事需要通過中介者通知:

使用:

在上述示例中,Mediator是中介者接口泪酱,定義了sendMessage:fromColleague:方法派殷。ConcreteMediator是具體的中介者類,實現(xiàn)了中介者接口墓阀,并在sendMessage:fromColleague:方法中根據(jù)不同的發(fā)送者通知其他同事對象毡惜。

Colleague是抽象同事類,其中包含了中介者對象斯撮,并定義了send:和receiveMessage:方法经伙。ConcreteColleague1和ConcreteColleague2是具體的同事類,繼承自抽象同事類勿锅,分別實現(xiàn)了具體的發(fā)送和接收行為帕膜。

在使用示例中,創(chuàng)建了一個具體的中介者對象mediator溢十,以及兩個具體的同事對象colleague1和colleague2垮刹。通過設(shè)置中介者的同事對象,并通過調(diào)用同事對象的send:方法發(fā)送消息张弛,觸發(fā)中介者對象的消息傳遞過程荒典。

當colleague1發(fā)送消息時酪劫,中介者對象mediator將消息傳遞給colleague2,colleague2收到消息后打印出來种蝶。同樣地契耿,當colleague2發(fā)送消息時,中介者對象mediator將消息傳遞給colleague1螃征,colleague1收到消息后打印出來搪桂。

這樣,通過中介者模式盯滚,對象之間的通信通過中介者進行集中處理踢械,實現(xiàn)了對象之間的解耦。

在iOS開發(fā)中魄藕,中介者模式常常應(yīng)用于以下場景:

視圖控制器之間的通信:在iOS應(yīng)用程序中内列,ViewController之間需要進行數(shù)據(jù)傳遞和交互。使用中介者模式可以將這些通信邏輯抽象到一個中介者對象中背率,視圖控制器只需要與中介者進行通信话瞧,而無需直接依賴其他視圖控制器。這樣可以降低視圖控制器之間的耦合度寝姿,使代碼更加清晰和可維護交排。

多個模塊之間的通信:在大型iOS應(yīng)用程序中,通常由多個模塊或組件組成饵筑,它們之間需要進行數(shù)據(jù)傳遞和交互埃篓。使用中介者模式可以引入一個中介者對象,用于集中處理模塊之間的通信根资。 模塊只需要與中介者進行通信架专,而無需了解其他模塊的具體細節(jié),從而實現(xiàn)模塊之間的解耦和靈活性玄帕。

從上面的應(yīng)用也可以看到部脚,中介者模式有減少對象之間耦合性增加復(fù)用性和擴展性集中控制交互邏輯的優(yōu)點桨仿。同時睛低,中介者模式也可能存在中介對象隨著通信的對象變多而變的復(fù)雜,臃腫服傍,難以維護钱雷,還有增加系統(tǒng)的復(fù)雜性的缺點。

九吹零、備忘錄模式(Memento Pattern)

備忘錄模式(Memento Pattern)用于在不破壞封裝性的前提下捕獲和恢復(fù)對象的內(nèi)部狀態(tài)罩抗。該模式通過創(chuàng)建一個備忘錄對象來存儲對象的狀態(tài),并將其保存在原始對象之外灿椅,以便在需要時恢復(fù)狀態(tài)套蒂。

在備忘錄模式中钞支,通常涉及三個主要角色:

發(fā)起人(Originator):它是需要保存狀態(tài)的對象。它可以創(chuàng)建一個備忘錄來保存當前狀態(tài)操刀,也可以使用備忘錄來恢復(fù)之前保存的狀態(tài)烁挟。

備忘錄(Memento):它是保存發(fā)起人對象狀態(tài)的對象。它通常具有能夠獲取發(fā)起人狀態(tài)的方法骨坑,以及設(shè)置發(fā)起人狀態(tài)的方法撼嗓。

管理者(Caretaker):它負責保存和恢復(fù)備忘錄對象。它通常會保存多個備忘錄對象欢唾,并可以選擇在適當?shù)臅r候?qū)⑵涮峁┙o發(fā)起人且警。

例子

使用:

在上述示例中,Originator代表發(fā)起人對象礁遣,它具有狀態(tài)屬性state斑芜。它通過createMemento方法創(chuàng)建一個備忘錄對象并保存當前狀態(tài),通過restoreFromMemento方法從備忘錄對象中恢復(fù)狀態(tài)祟霍。

Memento表示備忘錄對象杏头,它具有一個state屬性用于保存發(fā)起人的狀態(tài)。

Caretaker充當管理者對象沸呐,它負責保存和恢復(fù)備忘錄對象大州。它使用一個可變數(shù)組mementos來保存多個備忘錄對象,并提供了addMemento和getMementoAtIndex方法來添加和獲取備忘錄垂谢。

在使用備忘錄模式時,發(fā)起人可以創(chuàng)建備忘錄對象并將其交給管理者保存疮茄。如果需要恢復(fù)之前的狀態(tài)滥朱,可以從管理者那里獲取相應(yīng)的備忘錄對象,并通過發(fā)起人對象恢復(fù)狀態(tài)力试。這樣可以在不破壞封裝性的情況下實現(xiàn)狀態(tài)的保存和恢復(fù)徙邻。

備忘錄模式在iOS開發(fā)中常用于需要保存和恢復(fù)對象狀態(tài)的場景,尤其是在撤銷和恢復(fù)功能畸裳、數(shù)據(jù)持久化缰犁、界面狀態(tài)管理以及游戲狀態(tài)管理等方面。通過使用備忘錄模式怖糊,可以更好地控制對象的狀態(tài)帅容,并提供靈活的狀態(tài)管理機制。

可以看出伍伤,備忘錄模式具有狀態(tài)保存和恢復(fù)的分離并徘,支持撤銷和恢復(fù)的優(yōu)點,但同時扰魂,備忘錄模式也存在內(nèi)存消耗過大麦乞,會暴露對象原始屬性的缺點蕴茴。

十、狀態(tài)模式(State Pattern)

狀態(tài)模式(State Pattern)允許對象在內(nèi)部狀態(tài)改變時改變其行為姐直,使其看起來像是修改了自身的類倦淀。狀態(tài)模式通過將狀態(tài)封裝成獨立的類,使得狀態(tài)的變化不直接影響到對象的行為声畏,從而實現(xiàn)了狀態(tài)與行為的解耦撞叽。

在狀態(tài)模式中,對象根據(jù)內(nèi)部狀態(tài)的不同而改變其行為砰识。它包含以下主要角色:

Context(上下文):定義客戶端感興趣的接口能扒,并維護一個具體狀態(tài)類的實例,這個實例定義當前狀態(tài)辫狼。

State(狀態(tài)):定義一個接口初斑,用于封裝與Context的特定狀態(tài)相關(guān)的行為。

ConcreteState(具體狀態(tài)):每個具體狀態(tài)類實現(xiàn)State接口膨处,并實現(xiàn)與該狀態(tài)相關(guān)的行為见秤。

例子

假設(shè)我們正在構(gòu)建一個音樂播放器應(yīng)用,其中包含多個播放狀態(tài)(暫停真椿、播放鹃答、停止):

我們對于不同狀態(tài)的變換,只需要簡單使用MusicPlayer:

在上面的示例中突硝,我們定義了一個音樂播放器應(yīng)用的上下文類MusicPlayer和三個具體狀態(tài)類PlayState测摔、PauseState和StopState,它們實現(xiàn)了狀態(tài)接口State解恰。在MusicPlayer中锋八,我們通過維護一個currentState實例變量來跟蹤當前狀態(tài),并且在狀態(tài)改變時更新它护盈⌒矗客戶端代碼通過調(diào)用playMusic、pauseMusic和stopMusic等方法來操作音樂播放器腐宋,具體的行為由當前狀態(tài)對象處理紊服。

這樣,當我們需要添加新的播放狀態(tài)時胸竞,只需創(chuàng)建一個新的具體狀態(tài)類并實現(xiàn)相應(yīng)的行為方法欺嗤,而不需要修改MusicPlayer類的代碼,實現(xiàn)了狀態(tài)和行為的解耦卫枝。

在iOS 實際開發(fā)中剂府,狀態(tài)模式適用于對象有多個狀態(tài)且狀態(tài)之間有復(fù)雜的轉(zhuǎn)換邏輯的情況。(比如:視圖控制器生命周期管理:視圖控制器在其生命周期中經(jīng)歷多個狀態(tài)剃盾,如viewDidLoad腺占、viewWillAppear淤袜、viewDidAppear、viewWillDisappear等衰伯≌∠郏可以使用狀態(tài)模式來管理這些狀態(tài),并根據(jù)不同的狀態(tài)執(zhí)行相應(yīng)的操作意鲸,以實現(xiàn)良好的生命周期管理)它可以使代碼更加模塊化烦周、靈活和可擴展。但在簡單的場景中怎顾,引入狀態(tài)模式可能會過于復(fù)雜读慎,不切實際

十一槐雾、訪問者模式(Visitor Pattern)

訪問者模式(Visitor Pattern允許我們在不修改對象結(jié)構(gòu)的情況下定義對對象的新操作夭委。該模式適用于需要對一個復(fù)雜對象結(jié)構(gòu)中的各個元素進行不同操作的情況。

訪問者模式基于兩個核心概念:元素(Element訪問者(Visitor)募强。元素是一個具體對象結(jié)構(gòu)株灸,它定義了接受訪問者對象的方法。訪問者是一個表示新操作的對象擎值,它定義了訪問元素的方法慌烧。通過將訪問者對象傳遞給元素,元素可以將自身委托給訪問者來執(zhí)行特定的操作鸠儿。

例子

首先屹蚊,我們定義元素接口 Element,包含一個接受訪問者對象的方法 acceptVisitor::

接下來进每,我們定義訪問者接口 Visitor淑翼,其中包含了針對不同元素的訪問方法:

然后粘衬,我們定義兩個具體元素類 ConcreteElementA 和 ConcreteElementB豹悬,它們實現(xiàn)了 Element 接口衅胀,并根據(jù)需要調(diào)用訪問者的相應(yīng)方法:

然后,我們實現(xiàn)具體的訪問者類 ConcreteVisitor肉瓦,其中實現(xiàn)了對兩個具體元素的不同操作:

使用

當運行這段代碼時,將會輸出以下結(jié)果:

通過使用訪問者模式胃惜,我們可以將元素和操作進行解耦泞莉,使得新增操作時不需要修改元素的代碼。這提高了代碼的可擴展性和可維護性船殉。

需要注意的是鲫趁,訪問者模式在iOS開發(fā)中并不是一個經(jīng)常使用的模式,它通常用于處理復(fù)雜的對象結(jié)構(gòu)和操作利虫。在簡單的情況下挨厚,使用其他更簡單的設(shè)計模式可能更加合適堡僻。使用訪問者模式需要權(quán)衡代碼的復(fù)雜性和可維護性,確保它能夠帶來實際的好處疫剃。


iOS 24種設(shè)計模式 - Swift Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钉疫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子巢价,更是在濱河造成了極大的恐慌牲阁,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壤躲,死亡現(xiàn)場離奇詭異城菊,居然都是意外死亡,警方通過查閱死者的電腦和手機碉克,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門凌唬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人棉胀,你說我怎么就攤上這事法瑟。” “怎么了唁奢?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵霎挟,是天一觀的道長。 經(jīng)常有香客問我麻掸,道長酥夭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任脊奋,我火速辦了婚禮熬北,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诚隙。我一直安慰自己讶隐,他們只是感情好,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布久又。 她就那樣靜靜地躺著巫延,像睡著了一般。 火紅的嫁衣襯著肌膚如雪地消。 梳的紋絲不亂的頭發(fā)上炉峰,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音脉执,去河邊找鬼疼阔。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的婆廊。 我是一名探鬼主播迅细,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼否彩!你這毒婦竟也來了疯攒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤列荔,失蹤者是張志新(化名)和其女友劉穎敬尺,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贴浙,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡砂吞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了崎溃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜻直。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖袁串,靈堂內(nèi)的尸體忽然破棺而出概而,到底是詐尸還是另有隱情,我是刑警寧澤囱修,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布赎瑰,位于F島的核電站,受9級特大地震影響破镰,放射性物質(zhì)發(fā)生泄漏餐曼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一鲜漩、第九天 我趴在偏房一處隱蔽的房頂上張望源譬。 院中可真熱鬧,春花似錦孕似、人聲如沸踩娘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽养渴。三九已至,卻和暖如春臂拓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背习寸。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工胶惰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人霞溪。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓孵滞,卻偏偏與公主長得像中捆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子坊饶,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容