軟件設(shè)計(jì)原則-iOS

最近在搞代碼重構(gòu)业崖,這是一個(gè)很好的學(xué)習(xí)軟件設(shè)計(jì)原則委粉、設(shè)計(jì)模式呜师、架構(gòu)設(shè)計(jì)并實(shí)踐的機(jī)會(huì),本文是以一個(gè)iOS開發(fā)人員對(duì)軟件設(shè)計(jì)原則的一個(gè)概括總結(jié)贾节。

一汁汗、概況

軟件設(shè)計(jì)原則和設(shè)計(jì)模式是緊密相關(guān)的兩個(gè)概念,但它們有著不同的焦點(diǎn)和目的栗涂。軟件設(shè)計(jì)原則主要關(guān)注如何設(shè)計(jì)“好的”軟件知牌,強(qiáng)調(diào)的是架構(gòu)設(shè)計(jì)方面的規(guī)范和指導(dǎo)思想;而設(shè)計(jì)模式則是針對(duì)具體的問題和場(chǎng)景斤程,提供精細(xì)的解決方案角寸,這些方案包含了具體實(shí)現(xiàn)細(xì)節(jié)和代碼結(jié)構(gòu)。
軟件設(shè)計(jì)原則是指導(dǎo)軟件開發(fā)的通用規(guī)范和指導(dǎo)思想暖释,是從更高層面上指導(dǎo)軟件設(shè)計(jì)的袭厂。常見的軟件設(shè)計(jì)原則有SOLID原則墨吓、KISS原則球匕、DRY原則、YAGNI原則等等帖烘。

下面來(lái)對(duì)具體的"原則"做個(gè)了解.

二亮曹、SOLID原則

  • 開放封閉原則(Open Close Principle)
    對(duì)修改封閉,對(duì)擴(kuò)展開放。比如工廠方法模式和策略模式照卦,工廠方法模式通過(guò)定義一個(gè)抽象的工廠類來(lái)管理產(chǎn)品對(duì)象的實(shí)例化式矫,以便于在不改變?cè)写a的基礎(chǔ)上新增產(chǎn)品對(duì)象的類型。
    簡(jiǎn)單工廠役耕、工廠方法采转、抽象工廠設(shè)計(jì)模式-iOS

  • 依賴倒置原則(Dependence Inversion Principle)
    依賴于抽象,而不依賴于具體瞬痘。
    依賴倒置原則中的核心思想是:高層模塊不應(yīng)該依賴于低層模塊故慈,而雙方都應(yīng)該依賴于抽象。在UITableView中框全,我們可以看到UITableViewDataSourceUITableViewDelegate就是抽象察绷,而UITableView就是依賴于這兩個(gè)協(xié)議實(shí)現(xiàn)列表的數(shù)據(jù)源和代理。

  • 單一職責(zé)原則(Simple Responsibility Principle)
    設(shè)計(jì)的類只負(fù)責(zé)一種類型的職責(zé)津辩,只有一個(gè)引起它變化的原因拆撼。這樣可以使代碼更加清晰,避免出現(xiàn)過(guò)度復(fù)雜的繼承關(guān)系和耦合喘沿。比如在UIViewController中闸度,可以將不同類型的任務(wù)交給不同的類去實(shí)現(xiàn),保證職責(zé)單一蚜印,代碼也清晰易懂筋岛。

  • 接口隔離原則(interface Segregation Principle)
    用多個(gè)專門的接口,而不使用單一的總接口晒哄,客戶端不應(yīng)該依賴它不需要的接口睁宰。在設(shè)計(jì)時(shí)應(yīng)該注意:
    1)一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小接口上。
    2)建立單一接口寝凌,不要建立龐大臃腫的接口柒傻。
    3)盡量細(xì)化接口,接口中的方法盡量少(不是越少越好较木,而是適度)红符。

  • 里氏替換原則(Liskov Substitution Principle)
    要求程序中,使用基類的對(duì)象可以被其子類的對(duì)象所代替伐债,而不會(huì)產(chǎn)生任何錯(cuò)誤或異常预侯,使用者不需要關(guān)心實(shí)現(xiàn)的具體類。在iOS開發(fā)中峰锁,我們可以利用多態(tài)的特性萎馅,讓不同的子類對(duì)象通過(guò)父類來(lái)使用,從而增加代碼的靈活性和擴(kuò)展性虹蒋。

三糜芳、迪米特法則(Law of Demeter)

也稱最少知道原則飒货,Least Knowledge Principle, LKP
指一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象保持最少的了解峭竣,盡量降低類與類之間的耦合度塘辅。一個(gè)類應(yīng)依賴于那些最直接合理的類,而不是依賴于很多其他類皆撩。主要是:

  1. 一個(gè)對(duì)象只應(yīng)該調(diào)用直接朋友(即與其它對(duì)象有直接關(guān)系的對(duì)象)的方法扣墩。在對(duì)象之間建立一條明確的通信路徑可以降低耦合度,使系統(tǒng)更容易維護(hù)和修改扛吞。
  2. 謹(jǐn)慎使用外觀模式: 外觀模式可以幫助我們降低耦合性沮榜,但是在使用時(shí)需要注意,放置太多的業(yè)務(wù)邏輯代碼到外觀模式中會(huì)導(dǎo)致對(duì)象之間互相依賴喻粹,不利于擴(kuò)展和維護(hù)蟆融。
  3. 不暴露任何細(xì)節(jié):一個(gè)好的設(shè)計(jì)應(yīng)該將系統(tǒng)的實(shí)現(xiàn)細(xì)節(jié)封裝在類內(nèi)部,不向外暴露任何不必要的細(xì)節(jié)信息守呜。這樣可以降低類之間的耦合度型酥,使系統(tǒng)更加穩(wěn)定和靈活。
    例如:在iOS開發(fā)中查乒,UIView只知道與其相關(guān)聯(lián)的UIViewController弥喉,而不需要知道UIViewController背后的一層層業(yè)務(wù)邏輯和數(shù)據(jù)存儲(chǔ)的實(shí)現(xiàn),以此來(lái)實(shí)現(xiàn)類間的解耦合玛迄。另外一個(gè)例子是KVO.

四由境、合成復(fù)用原則(Composite/Aggregate Reuse Principle)

用組合和聚合關(guān)系來(lái)代替繼承實(shí)現(xiàn)代碼復(fù)用。這里的組合指的是通過(guò)將一個(gè)或多個(gè)對(duì)象(組合部分)組合成一個(gè)更大的蓖议、有著更高層次抽象的整體(組合整體)虏杰,而聚合則是指在一個(gè)類中引用另一個(gè)類的實(shí)例。

五勒虾、KISS原則(Keep It Simple And Stupid)

KISS原則強(qiáng)調(diào)在設(shè)計(jì)軟件時(shí)應(yīng)力求簡(jiǎn)單纺阔,避免復(fù)雜和不必要的細(xì)節(jié)和冗余,以保持代碼的簡(jiǎn)潔修然、易理解笛钝、可維護(hù)和可擴(kuò)展。

六愕宋、YAGNI原則(You Ain't Gonna Need It)

YAGNI原則是一種迭代開發(fā)和極限編程中的設(shè)計(jì)哲學(xué)玻靡,它告訴程序員不要在軟件中添加除了當(dāng)前需要之外的任何功能,避免浪費(fèi)時(shí)間和精力開發(fā)無(wú)用功能中贝,或在被證明是需要之前預(yù)測(cè)未來(lái)的需求囤捻。

七、DRY原則(Don’t Repeat Yourself)

DRY原則要求程序員避免代碼重復(fù)雄妥,避免重復(fù)造輪子最蕾,復(fù)用已有的模塊和代碼依溯。這可以幫助減少錯(cuò)誤率老厌,提高代碼的可讀性瘟则、可維護(hù)性和可擴(kuò)展性。

八枝秤、GRASP原則(General Responsibility Assignment Software Parren)

職責(zé)分配軟件模式醋拧,GRASP原則提供了一些模式和約束條件,幫助程序員正確分配和選擇各個(gè)類和對(duì)象所應(yīng)負(fù)責(zé)的職責(zé)淀弹,以提高代碼的可讀性丹壕、可維護(hù)性和可擴(kuò)展性。主要有以下九個(gè)

  • 建造者(Creator):盡量將對(duì)象的創(chuàng)建和初始化工作封裝到一個(gè)專門的類中薇溃。
  • 控制器(Controller):控制器模式用于協(xié)調(diào)和控制系統(tǒng)中的各種活動(dòng)和任務(wù)菌赖。
  • 信息專家(Infomation Export):?jiǎn)栴}的解決應(yīng)該由盡可能具有相關(guān)知識(shí)的對(duì)象來(lái)處理。
  • 低耦合(Low Coupling): 盡量減少不同對(duì)象之間的依賴關(guān)系沐序,從而降低耦合琉用。
  • 高內(nèi)聚(High Cohesion): 在單個(gè)對(duì)象中將相關(guān)的屬性和方法組織在一起,以提高其內(nèi)聚性策幼。
  • 間接性(Indirection): 使用一個(gè)中間對(duì)象來(lái)封裝和管理不同對(duì)象之間的通信邑时。
  • 多態(tài)性(Polymorphism): 通過(guò)多態(tài)來(lái)處理對(duì)象可能的狀態(tài)變化和狀態(tài)轉(zhuǎn)換,以增強(qiáng)程序的靈活性特姐。
  • 受保護(hù)的變化(Protected Variations): 在可能發(fā)生改變的地方創(chuàng)建保護(hù)殼晶丘,以防止變化對(duì)系統(tǒng)的影響。具體來(lái)說(shuō)唐含,它建議在設(shè)計(jì)類或模塊時(shí)浅浮,將可能受變化影響的部分封裝在一些具有抽象接口的類中,通過(guò)抽象層和多態(tài)性來(lái)限制變化對(duì)系統(tǒng)的影響捷枯,從而提高系統(tǒng)的可維護(hù)性和可擴(kuò)展性脑题。
  • 純虛構(gòu)(Pure Fabrication):創(chuàng)建一個(gè)虛擬的類或?qū)ο髞?lái)表示某種行為或任務(wù),并將其從任何現(xiàn)有的類中分離出來(lái)铜靶。

下面是對(duì)其中幾個(gè)不太好理解的原則的舉例說(shuō)明:

1. 接口隔離原則的實(shí)例

一個(gè)常見的應(yīng)用場(chǎng)景是網(wǎng)絡(luò)請(qǐng)求叔遂,我們可以通過(guò)封裝一個(gè)網(wǎng)絡(luò)請(qǐng)求庫(kù)來(lái)方便地對(duì)外提供網(wǎng)絡(luò)請(qǐng)求的功能。在實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求庫(kù)時(shí)争剿,我們可以應(yīng)用接口隔離原則已艰,將網(wǎng)絡(luò)請(qǐng)求接口拆分成更加細(xì)粒度的接口,如下所示:

protocol NetworkRequestProtocol {
    associatedtype ResponseDataType
    
    func get(url: URL, parameters: [String: Any]?,
             completion: ((Result<ResponseDataType, NetworkError>) -> Void)?)
    
    func post(url: URL, parameters: [String: Any]?,
              completion: ((Result<ResponseDataType, NetworkError>) -> Void)?)
}

protocol NetworkRequestConfigurableProtocol {
    func setHTTPHeaderFields(_ headers: [String: String])
    func setSerializationType(_ type: NetworkRequestSerializationType)
}
2. 間接性(Indirection)的實(shí)例

使用了MusicProvider這個(gè)中間對(duì)象作為間接層蚕苇。通過(guò)使用 MusicProvider對(duì)象哩掺,我們可以強(qiáng)制對(duì)歌曲訪問進(jìn)行驗(yàn)證,而不會(huì)直接使用 AudioPlayer 對(duì)象涩笤,從而實(shí)現(xiàn) Indirection 原則.

protocol MusicProviderProtocol {
    func playSong(_ song: Song, completionHandler: @escaping (Error?) -> Void)
}

class MusicProvider: MusicProviderProtocol {

    let audioPlayer: AudioPlayerProtocol
    let accessManager: AccessManagerProtocol

    init(audioPlayer: AudioPlayerProtocol, accessManager: AccessManagerProtocol) {
        self.audioPlayer = audioPlayer
        self.accessManager = accessManager
    }

    func playSong(_ song: Song, completionHandler: @escaping (Error?) -> Void) {
        guard accessManager.hasAccess(to: song) else {
            // 提示用戶登錄或升級(jí)賬戶以獲得足夠的訪問權(quán)限
            completionHandler(MyErrors.insufficientAccess)
            return
        }

        audioPlayer.play(song) { error in
            completionHandler(error)
        }
    }
}
3.受保護(hù)的變化(Protected Variations)原則的實(shí)例

假設(shè)我們正在開發(fā)一個(gè)iOS應(yīng)用程序嚼吞,該應(yīng)用程序包含一個(gè)視頻播放器功能盒件。我們希望能夠?qū)⒉煌囊曨l播放程序集成到應(yīng)用程序中,例如AVFoundation或第三方播放器SDK等舱禽。為了實(shí)現(xiàn)這個(gè)目標(biāo)炒刁,我們可以通過(guò)下面的方式來(lái)應(yīng)用Protected Variations原則:

我們創(chuàng)建一個(gè)名為VideoPlayerProtocol的協(xié)議,它定義了播放器的基本行為和接口誊稚。在具體的播放器類中翔始,我們將實(shí)現(xiàn)視頻播放的具體邏輯。協(xié)議和具體類的劃分允許我們?cè)谖磥?lái)從應(yīng)用程序中修改具體的播放器實(shí)現(xiàn)里伯,而無(wú)需改變播放器到應(yīng)用程序的接口城瞎。這可以為應(yīng)用程序帶來(lái)極大的靈活性和可維護(hù)性。

// VideoPlayerProtocol defines the interface for the video player
protocol VideoPlayerProtocol {
    var url: URL { get set }
    func play()
}

// We implement the VideoPlayerProtocol for AVFoundation
class AVFoundationVideoPlayer: VideoPlayerProtocol {
    var url: URL
    
    init(url: URL) {
        self.url = url
    }
    
    func play() {
        // Play with AVPlayer
    }
}

// We can add other video players using the same VideoPlayerProtocol
class ThirdPartyVideoPlayer: VideoPlayerProtocol {
    var url: URL
    
    init(url: URL) {
        self.url = url
    }
    
    func play() {
        // Play with third-party player SDK
    }
}
4. 純虛構(gòu)(Pure Fabrication)

通過(guò)PersistenceManagerAuthService兩個(gè)虛構(gòu)類將業(yè)務(wù)邏輯和非業(yè)務(wù)邏輯分離開來(lái)并提高代碼的復(fù)用性和可維護(hù)性疾瓮。

class AuthService {
  static let shared = AuthService()

  func validate(username: String, password: String, completion: @escaping (Bool) -> Void) {
    // 發(fā)送網(wǎng)絡(luò)請(qǐng)求并驗(yàn)證用戶名和密碼
    // 請(qǐng)求完成后調(diào)用 completion
  }
}

class PersistenceManager {
  static let shared = PersistenceManager()

  func save(user: User) {
    // 保存用戶信息
  }

  func load(completion: @escaping (User?) -> Void) {
    // 加載用戶信息
    // 加載完成后調(diào)用 completion
  }
}

class User {
  var username: String
  var email: String
  var password: String

  func signIn(completion: @escaping (Bool) -> Void) {
    AuthService.shared.validate(username: username, password: password) { isValid in
      completion(isValid)
    }
  }

  func save() {
    PersistenceManager.shared.save(user: self)
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脖镀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狼电,更是在濱河造成了極大的恐慌蜒灰,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漫萄,死亡現(xiàn)場(chǎng)離奇詭異卷员,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)腾务,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門毕骡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人岩瘦,你說(shuō)我怎么就攤上這事未巫。” “怎么了启昧?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵叙凡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我密末,道長(zhǎng)握爷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任严里,我火速辦了婚禮新啼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刹碾。我一直安慰自己燥撞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著物舒,像睡著了一般色洞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冠胯,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天火诸,我揣著相機(jī)與錄音,去河邊找鬼涵叮。 笑死惭蹂,一個(gè)胖子當(dāng)著我的面吹牛伞插,可吹牛的內(nèi)容都是我干的割粮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼媚污,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舀瓢!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起耗美,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤京髓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后商架,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堰怨,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昭躺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年迷雪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了需忿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丸凭。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡砚哗,死狀恐怖征讲,靈堂內(nèi)的尸體忽然破棺而出狸窘,到底是詐尸還是另有隱情阴幌,我是刑警寧澤饿肺,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布蒋困,位于F島的核電站,受9級(jí)特大地震影響敬辣,放射性物質(zhì)發(fā)生泄漏雪标。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一溉跃、第九天 我趴在偏房一處隱蔽的房頂上張望村刨。 院中可真熱鬧,春花似錦喊积、人聲如沸烹困。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)髓梅。三九已至拟蜻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枯饿,已是汗流浹背酝锅。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奢方,地道東北人搔扁。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蟋字,于是被迫代替她去往敵國(guó)和親稿蹲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

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