swift中的封裝設(shè)計(jì)模式

提問(wèn):是否理解為什么緊密耦合是一個(gè)很大的問(wèn)題街图?

// 產(chǎn)品
var products = [
    ("Kayak", "A boat for one person", 275.0, 10),
    ("Lifejacket", "Protective and fashionable", 48.95, 14),   
    ("Soccer Ball", "FIFA-approved size and weight", 19.5, 32)]
 
// 費(fèi)率
func calculateTax(product:(String, String, Double, Int)) -> Double {
    return product.2 * 0.2;
}
 
// 股票的價(jià)值
func calculateStockValue(tuples:[(String, String, Double, Int)]) -> Double {
    return tuples.reduce(0, {
        (total, product) -> Double in
            return total + (product.2 * Double(product.3))
    });
}  

// 輸出
print("Sales tax for Kayak: $\(calculateTax(products[0]))"); 
print("Total value of stock: $\(calculateStockValue(products))");

  • 緊密耦合的組件會(huì)讓代碼難以維護(hù),比如上面的代碼如果需要改變產(chǎn)品就會(huì)變得很麻煩懒构,所以必須要進(jìn)行更改餐济,并測(cè)試它們的影響。在一個(gè)組件中的改變要求改變那些依賴其執(zhí)行胆剧。如果在應(yīng)用程序中包含大量的緊耦合絮姆,那么我們可以通過(guò)修改代碼醉冤,級(jí)聯(lián)和制作一個(gè)簡(jiǎn)單的修正或添加新功能的行為來(lái)避免成為大量的重寫(xiě)伏筆,松散耦合的組件在設(shè)計(jì)模式中的一個(gè)關(guān)鍵目標(biāo)篙悯。
E970A837-F775-4DB5-B73B-C0BB7C00747A.png

我刪除了描述產(chǎn)品的價(jià)值和突出顯示的語(yǔ)句顯示所需要的功能的相應(yīng)變革蚁阳。在實(shí)際項(xiàng)目中,這些變化可以裝載鸽照,以及大量更改螺捐,如果它們影響到其他緊密耦合,然后可以導(dǎo)致代碼被修改的應(yīng)用程序中很大一部分矮燎。這一級(jí)別的變化很難管理定血,需要進(jìn)行全面的測(cè)試,以確保始終如一地應(yīng)用了更改诞外,所做的更改沒(méi)有引入任何新的 bug澜沟。
了解對(duì)象模板模式
對(duì)象模板模式使用類或結(jié)構(gòu)定義從中創(chuàng)建對(duì)象的模板。當(dāng)應(yīng)用程序組件需要一個(gè)對(duì)象時(shí)峡谊,它呼吁swift運(yùn)行時(shí)創(chuàng)建通過(guò)指定模板和配置對(duì)象所需的任何運(yùn)行時(shí)初始化數(shù)據(jù)值的名稱茫虽。

對(duì)象模板模式:

1.第一個(gè)操作是調(diào)用組件要求swift運(yùn)行時(shí)創(chuàng)建一個(gè)對(duì)象,提供要使用的模板和自定義將創(chuàng)建該對(duì)象所需的任何運(yùn)行時(shí)數(shù)據(jù)值的名稱靖苇。
2.第二次操作席噩,swift運(yùn)行時(shí)分配存儲(chǔ)該對(duì)象所需的內(nèi)存,并使用該模板來(lái)創(chuàng)建它贤壁。模板包含用于準(zhǔn)備對(duì)象設(shè)置所使用的初始狀態(tài)、 通過(guò)提供調(diào)用組件的運(yùn)行時(shí)值或模板 (或兩者) 中, 定義的值的初始值設(shè)定項(xiàng)方法和swift運(yùn)行時(shí)調(diào)用初始值設(shè)定項(xiàng)準(zhǔn)備使用的對(duì)象埠忘。在最后一個(gè)操作脾拆,swift運(yùn)行時(shí)將它已經(jīng)創(chuàng)建的對(duì)象給調(diào)用的組件。這三個(gè)步驟的過(guò)程莹妒,我們均可以一遍遍重復(fù)名船,單個(gè)模板可用于創(chuàng)建多個(gè)對(duì)象。
了解類結(jié)構(gòu)旨怠、 對(duì)象和實(shí)例
有些的面向?qū)ο缶幊绦g(shù)語(yǔ)中所使用松散的日常開(kāi)發(fā)但理解設(shè)計(jì)模式的時(shí)候渠驼,那可能會(huì)造成混淆。這種模式的關(guān)鍵條件是類鉴腻、結(jié)構(gòu)迷扇、對(duì)象和實(shí)例.
類和結(jié)構(gòu)都是這兩個(gè)模板,它們是swift如下對(duì)象模板模式的食譜爽哎。swift跟隨在模板中的說(shuō)明創(chuàng)建新對(duì)象蜓席。可以重復(fù)使用相同的模板來(lái)創(chuàng)建多個(gè)對(duì)象课锌。每個(gè)對(duì)象是不同的但它創(chuàng)建使用相同的指令厨内,就像一個(gè)食譜可以用于創(chuàng)建多個(gè)蛋糕 (添加一個(gè) Int,一種方法來(lái)更改它的值,等等)雏胃。
Word實(shí)例具有相同的含義為對(duì)象请毛,但它用來(lái)指用于所以創(chuàng)建該對(duì)象的圖案的名稱,產(chǎn)品也可以調(diào)用對(duì)象的一個(gè)實(shí)例產(chǎn)品班上
重要的一點(diǎn)是瞭亮,類和結(jié)構(gòu)是你寫(xiě)在開(kāi)發(fā)過(guò)程中的說(shuō)明進(jìn)行操作方仿,對(duì)象創(chuàng)建時(shí)應(yīng)用程序。當(dāng)您更改存儲(chǔ)一個(gè)對(duì)象的值時(shí)街州,例如兼丰,它不會(huì)更改用于創(chuàng)建它的圖案。

創(chuàng)建模板類(封裝一個(gè)類)
新建一個(gè)名字叫做 Product 的類

Product.swift File 的內(nèi)容

class Product {
    var name:String;
    var description:String;
    var price:Double;
    var stock:Int;
    init(name:String, description:String, price:Double, stock:Int) {
        self.name = name;
        self.description = description;
        self.price = price;
        self.stock = stock;
    }
}

上面的方法盡封裝了一個(gè)簡(jiǎn)單的類唆缴,接著我會(huì)加入功能鳍征,然后再原來(lái)的文件中進(jìn)行重構(gòu)賦值。

// 產(chǎn)品通過(guò)重寫(xiě)的一個(gè)產(chǎn)品類來(lái)進(jìn)行重新賦值
var products = [
    Product(name: "Kayak", description: "A boat for one person",
        price: 275, stock: 10),
    Product(name: "Lifejacket", description: "Protective and fashionable",
        price: 48.95, stock: 14),
    Product(name: "Soccer Ball", description: "FIFA-approved size and weight",
        price: 19.5, stock: 32)];

func calculateTax(product:Product) -> Double {
    return product.price * 0.2;
}
 
func calculateStockValue(productsArray:[Product]) -> Double {
    return productsArray.reduce(0, {(total, product) -> Double in
            return total + (product.price * Double(product.stock))
}); }

print("Sales tax for Kayak: $\(calculateTax(products[0]))");
print("Total value of stock: $\(calculateStockValue(products))");

PS:封裝一個(gè)類面徽,其實(shí)就是通過(guò)定義一個(gè)模板需要的屬性來(lái)進(jìn)行工作艳丛,這樣有非常多的好處,在面對(duì)對(duì)象的編程使用類和結(jié)構(gòu)體是一個(gè)更快更直接的方法趟紊,使用模板時(shí)氮双,就有兩個(gè)步驟 ︰ 定義模板并創(chuàng)建對(duì)象使用的模板。

上面的代碼是非常簡(jiǎn)單的霎匈。它沒(méi)有功能戴差,只是封裝了類和結(jié)構(gòu),但它證明了即使是最簡(jiǎn)單的模板也可以減少變化的影響铛嘱。那么這個(gè)時(shí)候我們來(lái)刪除一些數(shù)據(jù)就非常方便了暖释。
從產(chǎn)品類中刪除屬性

class Product {
    var name:String;
    var price:Double;
    var stock:Int;
    init(name:String, price:Double, stock:Int) {
        self.name = name;
        self.price = price;
        self.stock = stock;
} }

這里是刪除了詳情說(shuō)明

var products = [
    Product(name: "Kayak", price: 275, stock: 10),
    Product(name: "Lifejacket", price: 48.95, stock: 14),
    Product(name: "Soccer Ball", price: 19.5, stock: 32)]

func calculateTax(product:Product) -> Double {
    return product.price * 0.2;
}

func calculateStockValue(productsArray:[Product]) -> Double {
    return productsArray.reduce(0, {
        (total, product) -> Double in
            return total + (product.price * Double(product.stock))
}); }

print("Sales tax for Kayak: $\(calculateTax(products[0]))");
print("Total value of stock: $\(calculateStockValue(products))");

現(xiàn)在的代碼失去了詳情的說(shuō)明。但是calculateTax 和 calculateStockValue 在所有墨吓,并且每個(gè)功能的因?yàn)槊總€(gè)類中的屬性是定義和訪問(wèn)獨(dú)立于其他屬性既不函數(shù)依賴于描述屬性球匕。
使用類和結(jié)構(gòu)限制只是直接受到影響的變化,防止使用不太結(jié)構(gòu)化的數(shù)據(jù)類型帖烘。

封裝的好處

從數(shù)據(jù)對(duì)象作為模板亮曹,使用類或結(jié)構(gòu)中最重要的好處是對(duì)封裝的支持。
封裝是面向?qū)ο缶幊痰暮诵乃枷胫幻刂ⅲ羞@種想法的軸承對(duì)這一章的兩個(gè)方面照卦。
第一個(gè)方面是,封裝允許的數(shù)據(jù)值和操作這些值將被結(jié)合到單個(gè)組件中的邏輯历极。結(jié)合數(shù)據(jù)和邏輯使得它易于閱讀的代碼窄瘟,因?yàn)橐磺杏嘘P(guān)的數(shù)據(jù)類型定義在相同的地方。現(xiàn)在要加上一些邏輯趟卸。
在 Product.swift File 中添加邏輯

class Product {
    var name:String;
    var price:Double;
    var stock:Int;
    init(name:String, price:Double, stock:Int) {
        self.name = name;
        self.price = price;
        self.stock = stock;
}
    //計(jì)算匯率的方法
    func calculateTax(rate: Double) -> Double {
        return self.price * rate;
}
    //股票價(jià)值
    var stockValue: Double {
        get {
            return self.price * Double(self.stock);
        }
}
}

我增加了calculateTax方法蹄葱,它接受稅率作為參數(shù)氏义,用它來(lái)計(jì)算銷售稅,和stockValue計(jì)算得出的特性图云,實(shí)現(xiàn) getter 子句惯悠,計(jì)算該股票的總價(jià)值。
我更新的代碼語(yǔ)句 main.swift 文件和操作產(chǎn)品反對(duì)使用新的方法和屬性竣况,更新 main.swift 文件中的代碼

var products = [
    Product(name: "Kayak", price: 275, stock: 10),
    Product(name: "Lifejacket", price: 48.95, stock: 14),
    Product(name: "Soccer Ball", price: 19.5, stock: 32)]

func calculateStockValue(productsArray:[Product]) -> Double {
    return productsArray.reduce(0, {(total, product) -> Double in
            return total + product.stockValue}) 
}

print("Sales tax for Kayak: $\(products[0].calculateTax(0.2))");
print("Total value of stock: $\(calculateStockValue(products))");

這些看似簡(jiǎn)單的變化克婶,但一些重要的事情發(fā)生了︰
產(chǎn)品類現(xiàn)在有public的演示文稿和私有的實(shí)現(xiàn)

產(chǎn)品類的publicprivate方面
public是其他組件可以使用的 API。任何組件可以獲取或設(shè)置的值名稱, 價(jià)格丹泉,和股票屬性在任何他們需要的方式中使用它們情萤。
public還包括 stockValue 屬性和 calculateTax 方法,但是 — — 這是重要的部分 — — 不是它們的實(shí)現(xiàn)摹恨。
提示不要混淆使用的私有實(shí)現(xiàn)想法private關(guān)鍵字筋岛。private關(guān)鍵字限制可以使用的類、 方法或?qū)傩陨购澹词巩?dāng)private不使用關(guān)鍵字睁宰、 實(shí)施方法和計(jì)算的屬性不可見(jiàn)到調(diào)用組件。
能力呈現(xiàn)屬性或方法寝凌,而又不暴露其執(zhí)行容易打破緊密耦合柒傻,因?yàn)樗遣豢赡艿牧硪唤M件將取決于執(zhí)行。作為一個(gè)例子较木,我是如何改變的執(zhí)行 calculateTax 方法來(lái)定義最大的稅額红符。因?yàn)樵趫?zhí)行執(zhí)行計(jì)算產(chǎn)品對(duì)象,變化是肉眼看不到其他元件伐债,因此相信產(chǎn)品類知道如何執(zhí)行其計(jì)算违孝。
改變?cè)?Product.swift File 中的方法實(shí)現(xiàn)

func calculateTax(rate: Double) -> Double {
    return min(10, self.price * rate);
}

我用函數(shù)從swift的標(biāo)準(zhǔn)庫(kù),設(shè)置了銷售稅 10 美元的最高限量泳赋。我有只顯示 calculateTax 方法在清單,因?yàn)闆](méi)有其他代碼語(yǔ)句在playground上不得不改變喇喉,以適應(yīng)新的稅計(jì)算; 變化是在私有實(shí)現(xiàn)部分的產(chǎn)品類祖今,與其他組件都無(wú)法創(chuàng)建依賴項(xiàng)。運(yùn)行該應(yīng)用程序會(huì)產(chǎn)生以下結(jié)果 ︰

皮劃艇的銷售稅: $10.0
總價(jià)值的股票: $4059.3

擴(kuò)展public的好處
A 的 Swift 不錯(cuò)的功能是你可以進(jìn)化隨著時(shí)間流逝拣技,更改應(yīng)用程序類的public演示文稿的方式千诬。由此看來(lái), 股票屬性是一個(gè)標(biāo)準(zhǔn)的存儲(chǔ)的屬性膏斤,可以設(shè)置為任何 Int 值徐绑,但它沒(méi)有意義的股票,有負(fù)的項(xiàng)目數(shù)莫辨,這樣做會(huì)影響所返回的結(jié)果 stockValue 計(jì)算屬性傲茄。
swift允許我無(wú)縫地替代股票-存儲(chǔ)屬性計(jì)算的屬性毅访,其實(shí)現(xiàn)可以強(qiáng)制驗(yàn)證策略,以確保庫(kù)存水平是永遠(yuǎn)不會(huì)小于零盘榨。在 Product.swift File 中添加一個(gè)計(jì)算的屬性

class Product {
var name:String;
var price:Double;
private var stockBackingValue:Int = 0;
    var stock:Int {
        get {
            return stockBackingValue;
        }
        set {
            stockBackingValue = max(0, newValue);
} }
    init(name:String, price:Double, stock:Int) {
        self.name = name;
        self.price = price;
        self.stock = stock;
}
    func calculateTax(rate: Double) -> Double {
        return min(10, self.price * rate);
}
    var stockValue: Double {
        get {
            return self.price * Double(self.stock);
        }
} }

我定義了一個(gè)支持變量將保存的值股票屬性和已經(jīng)取代了存儲(chǔ)股票具有計(jì)算具有屬性的屬性 getter 和 setter 的屬性喻粹。吸氣劑只是返回屬性的值的支持,我有被命名為 stockBackingValue草巡,但二傳手使用從標(biāo)準(zhǔn)庫(kù)將支持值設(shè)置為零守呜,當(dāng)負(fù)的值用來(lái)設(shè)置該屬性的最大功能。這種變化的影響的確是的public和private部分的產(chǎn)品類有改變山憨,但這不會(huì)影響代碼的方式查乒,使用的類

存儲(chǔ)的屬性更改為計(jì)算屬性的影響在 main.swift 文件中檢查驗(yàn)證

var products = [
    Product(name: "Kayak", price: 275, stock: 10),
    Product(name: "Lifejacket", price: 48.95, stock: 14),
    Product(name: "Soccer Ball", price: 19.5, stock: 32)];
func calculateStockValue(productsArray:[Product]) -> Double {
    return productsArray.reduce(0, {(total, product) -> Double in
}
    return total + product.stockValue;
}); 
print("Sales tax for Kayak: $\(products[0].calculateTax(0.2))"); 
print("Total value of stock: $\(calculateStockValue(products))"); 
products[0].stock = -50;
print("Stock Level for Kayak: \(products[0].stock)");

我在playground上測(cè)試末尾添加兩個(gè)語(yǔ)句股票屬性的負(fù)值,但沒(méi)有其他變化處理能力是必需的郁竟。尤其是玛迄,代碼語(yǔ)句,依靠股票屬性都不知道從存儲(chǔ)的屬性為一個(gè)計(jì)算的變化枪孩。下面是示例應(yīng)用程序運(yùn)行時(shí)產(chǎn)生的控制臺(tái)輸出 ︰

皮劃艇的銷售稅: $10.0
總價(jià)值的股票: $4059.3
庫(kù)存水平的皮劃艇 ︰ 0
最后一條消息顯示計(jì)算屬性的效果 ︰ 我設(shè)置股票屬性設(shè)置為-50憔晒,但該屬性值的時(shí)候,我收到0.

理解的模式的陷阱

要避免的缺陷與此模式選擇模板蔑舞,錯(cuò)誤的這通常意味著要使用結(jié)構(gòu)拒担,當(dāng)一個(gè)類會(huì)更合適。swift的類和結(jié)構(gòu)有很多共同之處攻询,但還有一個(gè)重要的區(qū)別从撼,
在這種模式下 ︰ 結(jié)構(gòu)是值對(duì)象和類的引用對(duì)象。
在可可對(duì)象模板模式的示例
因?yàn)檫@是一個(gè)基本的模式钧栖,類和結(jié)構(gòu)可以發(fā)現(xiàn)整個(gè)可可框架和內(nèi)置swift類型低零。作為結(jié)構(gòu),實(shí)現(xiàn)基本的類型拯杠,如字符串掏婶、 數(shù)組和字典和類用于表示一切從網(wǎng)絡(luò)連接到用戶界面組件。我不會(huì)對(duì)列表中所有的類和結(jié)構(gòu)潭陪,用于 iOS 和可可框架雄妥,但是如果你想要如何一種深深植根這種模式是在 iOS 開(kāi)發(fā),看一看我用于創(chuàng)建 SportsStore 應(yīng)用程序的類依溯。除了產(chǎn)品類我創(chuàng)建了在這一章老厌,我有依靠 NSNumberFormatter 格式化貨幣字符串 UIViewController 來(lái)管理應(yīng)用程序和類,如所提的意見(jiàn) UILabel, UITextField黎炉,和 UIStepper 來(lái)預(yù)設(shè)布局組件向用戶枝秤。
將模式應(yīng)用到 SportsStore 應(yīng)用程序
準(zhǔn)備示例應(yīng)用程序
創(chuàng)建一個(gè)文件,我將使用定義并不直接相關(guān)慷嗜,設(shè)計(jì)模式的實(shí)用功能淀弹。要將新文件添加到項(xiàng)目丹壕,控制-點(diǎn)擊 SportsStore 文件夾項(xiàng)目導(dǎo)航器中,從菜單中選擇新的文件垦页。Xcode 將呈現(xiàn)不同的文件類型雀费,

選擇從 iOS 的 Swift 文件?源類別并單擊下一步按鈕。設(shè)置文件名稱為 Utils.swift 痊焊,并確保 SportsStore 在目標(biāo)列表中盏袄,選中,

創(chuàng)建的 Product.swift 文件
Xcode 將創(chuàng)建新文件并打開(kāi)它進(jìn)行編輯薄啥。 如何使用該文件來(lái)定義 Utils 類辕羽。
Utils.swift File 的內(nèi)容

import Foundation;
class Utils {
    class func currencyStringFromNumber(number:Double) -> String {
        let formatter = NSNumberFormatter();
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle;
        return formatter.stringFromNumber(number) ?? "";
} }

我定義了調(diào)用的方法類型 (也稱為靜態(tài)方法)currencyStringFromNumber接受雙值和數(shù)字格式設(shè)置為貨幣值的回報(bào)。例如垄惧,值 1000.1 將格式化為字符串 $1,000.10刁愿。(貨幣符號(hào)是基于應(yīng)用的設(shè)備的區(qū)域設(shè)置。在美國(guó)到逊,美元符號(hào)可能被替換另一個(gè)符號(hào)铣口,如那些為歐元或英鎊。)
字符串的格式不是我描述在此表中觉壶,所以我已經(jīng)定義在此代碼的模式的一部分Utils.swift要保持它的出路的文件脑题。
當(dāng)我將添加到底部的 SportsStore 布局標(biāo)簽所顯示的信息,我將使用新的類型方法铜靶。

創(chuàng)建產(chǎn)品類
正如我在"理解 Swift 訪問(wèn)控制"邊欄叔遂,解釋private關(guān)鍵字限制訪問(wèn)并不在同一個(gè)類文件中定義的代碼。因?yàn)槲蚁胍獜?qiáng)調(diào)由這種模式提供的公鑰/私鑰分離争剿,要?jiǎng)?chuàng)建一個(gè)新文件并使用它來(lái)定義產(chǎn)品類已艰。在上一節(jié)中描述的過(guò)程添加一個(gè)文件稱為 Product.swift SportsStore 項(xiàng)目并使用它來(lái)定義類。
Product.swift File 的內(nèi)容

class Product {
    private(set) var name:String;
    private(set) var description:String;
    private(set) var category:String;
    private var stockLevelBackingValue:Int = 0;
    private var priceBackingValue:Double = 0;
    init(name:String, description:String, category:String, price:Double,
        stockLevel:Int) {
            self.name = name;
            self.description = description;
            self.category = category;
            self.price = price;
            self.stockLevel = stockLevel;
}
    var stockLevel:Int {
        get { return stockLevelBackingValue;}
        set { stockLevelBackingValue = max(0, newValue);}
}
    private(set) var price:Double {
        get { return priceBackingValue;}
        set { priceBackingValue = max(1, newValue);}
}
    var stockValue:Double {
        get {
            return price * Double(stockLevel);
        }
} } 

提出了重點(diǎn)是public的表示與private實(shí)施蚕苇,取得了在幾種方法的分離所示的類哩掺。第一種方法是通過(guò)對(duì)添加注釋的屬性與private或 private(set)。private關(guān)鍵字可以隱藏不管它適用于從代碼在當(dāng)前文件涩笤,及這效果的制作 priceBackingValue 和 stockLevelBackingValue 屬性完全看不到 SportsStore 應(yīng)用的其余部分因?yàn)楫a(chǎn)品類是唯一永恒的東西 Product.swift 文件疮丛。
注釋具有的屬性private(set)意味著屬性可以從同一模塊中的其他文件中的代碼讀取,但只有在由代碼設(shè)置Product.swift文件辆它。我用 private(set) 的屬性在清單 4-13,大部分具有允許履恩,否則為不得設(shè)置使用傳遞給類初始值設(shè)定項(xiàng)的參數(shù)值的效果锰茉。
提示可有類似的效果,使用常量切心,但是我想要強(qiáng)調(diào)在這一章飒筑,對(duì)象模板模式和private(set)是一個(gè)更有用的例子片吊。
我用另一個(gè)方法是計(jì)算屬性,該屬性定義了只有獲取子句协屡。計(jì)算屬性的實(shí)現(xiàn)是private的即使該屬性本身是整個(gè)當(dāng)前模塊可用俏脊。

了解快速訪問(wèn)控制

swift以不尋常的方法來(lái)訪問(wèn)控制,能夠找出粗心肤晓。有三個(gè)級(jí)別的訪問(wèn)控制爷贫,這使用應(yīng)用public, private,和internal關(guān)鍵字补憾。private關(guān)鍵字是限制性最強(qiáng)的; 它限制對(duì)類漫萄、 結(jié)構(gòu)方法和屬性的定義在同一文件中的代碼訪問(wèn)。限制訪問(wèn)每個(gè)文件的基礎(chǔ)上從大多數(shù)語(yǔ)言的不同方法盈匾,并且意味著private在 Xcode 沒(méi)有影響
兒童游樂(lè)場(chǎng)腾务。
internal關(guān)鍵字表示當(dāng)前模塊內(nèi)允許訪問(wèn)。這是默認(rèn)級(jí)別的訪問(wèn)控制削饵,如果沒(méi)有關(guān)鍵字應(yīng)用使用岩瘦。對(duì)于大多數(shù)的 iOS 開(kāi)發(fā), internal保護(hù)會(huì)允許類窿撬、 結(jié)構(gòu)启昧、 方法、 函數(shù)或?qū)傩杂糜谡麄€(gè)項(xiàng)目的效果尤仍。
public關(guān)鍵字適用限制性最小的控制級(jí)別箫津,并允許從任何地方,包括當(dāng)前模塊外部訪問(wèn)宰啦。這是給開(kāi)發(fā)商誰(shuí)正在創(chuàng)建框架和誰(shuí)將需要使用的大多數(shù)使用的public關(guān)鍵字定義的框架給其他開(kāi)發(fā)人員提供了 API苏遥。
如果你已經(jīng)搬到swift從一種語(yǔ)言如 C# 或 Java,然后你可以最密切重新創(chuàng)建你習(xí)慣于通過(guò)定義每個(gè)類或結(jié)構(gòu)在其自己的訪問(wèn)控制.swift文件和使用private和internal的訪問(wèn)級(jí)別赡模。

ViewController.swift File 中的產(chǎn)品類

import UIKit
class ProductTableCell : UITableViewCell {
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var stockStepper: UIStepper!
    @IBOutlet weak var stockField: UITextField!
    var product:Product?;
}
class ViewController: UIViewController, UITableViewDataSource {
    @IBOutlet weak var totalStockLabel: UILabel!
    @IBOutlet weak var tableView: UITableView!
    var products = [
        Product(name:"Kayak", description:"A boat for one person",
            category:"Watersports", price:275.0, stockLevel:10),
        Product(name:"Lifejacket", description:"Protective and fashionable",
            category:"Watersports", price:48.95, stockLevel:14),
        Product(name:"Soccer Ball", description:"FIFA-approved size and weight",
            category:"Soccer", price:19.5, stockLevel:32),
        Product(name:"Corner Flags",
            description:"Give your playing field a professional touch",
            category:"Soccer", price:34.95, stockLevel:1),
        Product(name:"Stadium", description:"Flat-packed 35,000-seat stadium",
            category:"Soccer", price:79500.0, stockLevel:4),
        Product(name:"Thinking Cap",
            description:"Improve your brain efficiency by 75%",
            category:"Chess", price:16.0, stockLevel:8),
        Product(name:"Unsteady Chair",
            description:"Secretly give your opponent a disadvantage",
            category: "Chess", price: 29.95, stockLevel:3),
        Product(name:"Human Chess Board",
            description:"A fun game for the family", category:"Chess",
            price:75.0, stockLevel:2),
        Product(name:"Bling-Bling King",
            description:"Gold-plated, diamond-studded King",
            category:"Chess", price:1200.0, stockLevel:4)];
 
override func viewDidLoad() {
    super.viewDidLoad()
    displayStockTotal();
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView,
    numberOfRowsInSection section: Int) -> Int {
    return products.count;
}
func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let product = products[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("ProductCell") as ProductTableCell
cell.product = products[indexPath.row]
cell.nameLabel.text = product.name
cell.descriptionLabel.text = product.description
cell.stockStepper.value = Double(product.stockLevel)
cell.stockField.text = String(product.stockLevel)
return cell;
}
@IBAction func stockLevelDidChange(sender: AnyObject) {
    if var currentCell = sender as? UIView {
        while (true) {
            currentCell = currentCell.superview!;
            if let cell = currentCell as? ProductTableCell {
                if let product = cell.product? {
                    if let stepper = sender as? UIStepper {
                        product.stockLevel = Int(stepper.value);
                    } else if let textfield = sender as? UITextField {
                        if let newValue = textfield.text.toInt()? {
                            product.stockLevel = newValue;
} }
                    cell.stockStepper.value = Double(product.stockLevel);
                    cell.stockField.text = String(product.stockLevel);
}
break; }
}
        displayStockTotal();
    }
} 
func displayStockTotal() {
let stockTotal = products.reduce(0,
{(total, product) -> Int in return total + product.stockLevel}); totalStockLabel.text = "\(stockTotal) Products in Stock";
} }

過(guò)渡到使用產(chǎn)品類是簡(jiǎn)單的田炭。在編寫(xiě)代碼清單 4-14,我開(kāi)始用在類產(chǎn)品數(shù)據(jù)數(shù)組漓柑,然后修正所有的編譯器錯(cuò)誤教硫,直到被替換了對(duì)元組的所有引用。這是一個(gè)乏味而且容易出錯(cuò)的過(guò)程辆布,這就是為什么它是一個(gè)好的主意瞬矩,開(kāi)始與類和結(jié)構(gòu)的一個(gè)項(xiàng)目,如果你能 (某物锋玲,可悲的是景用,并不總是可行時(shí)接管現(xiàn)有的代碼)。
確保視圖和模型分離
有幾個(gè)點(diǎn)要注意有關(guān)清單 4-14 中的代碼惭蹂。第一個(gè)是伞插,
ViewController.swift文件定義了一個(gè)名為類ProductTableCell用于包含表示應(yīng)用程序布局中的產(chǎn)品的 UI 組件的引用割粮,并找到一種產(chǎn)品,當(dāng)用戶更改庫(kù)存水平媚污。在清單 4-14舀瓢,我取代提到一個(gè)元組中的索引位置變量產(chǎn)品數(shù)組引用產(chǎn)品對(duì)象相反,像這樣 ︰

class ProductTableCell : UITableViewCell {
   @IBOutlet weak var nameLabel: UILabel!
   @IBOutlet weak var descriptionLabel: UILabel!
   @IBOutlet weak var stockStepper: UIStepper!
   @IBOutlet weak var stockField: UITextField!
   var product:Product?;
}

你可能想知道為什么我沒(méi)有結(jié)合ProductTableCell與產(chǎn)品類耗美,并有一個(gè)單一的實(shí)體表示產(chǎn)品和用來(lái)顯示它的 UI 組件京髓。我解釋第 5 部分詳細(xì)的原因,當(dāng)我描述模型幽歼,視圖朵锣,控制器 (MVC) 模式,但簡(jiǎn)短的回答是很好的實(shí)踐甸私,它呈現(xiàn)給用戶 (在 MVC 的說(shuō)法诚些,將模型與視圖分離) 的方式從應(yīng)用程序中對(duì)數(shù)據(jù)進(jìn)行分離。執(zhí)行這種分離允許更容易地以不同的方式顯示相同數(shù)據(jù)皇型。我可能需要第二個(gè)視圖添加到應(yīng)用程序诬烹,在網(wǎng)格中,提出了產(chǎn)品和不經(jīng)分離模型和視圖之間弃鸦,組合的類需要能夠?qū)γ總€(gè)參與這兩種觀點(diǎn)的很快變得笨拙 UI 組件的引用并使應(yīng)用更改一個(gè)棘手且容易出錯(cuò)的過(guò)程绞吁。
擴(kuò)大摘要顯示
我一直在批評(píng)的元組在整個(gè)這一章,但他們可以當(dāng)他們使用在自足的方式唬格,而不是代表整個(gè)應(yīng)用程序范圍的數(shù)據(jù)的一種有用的語(yǔ)言功能家破。
你可以看到一個(gè)例子的怎樣使用元組。
我已經(jīng)改變了的執(zhí)行 displayStockTotal 方法的 ViewController 類购岗,以便單個(gè)調(diào)用到全球減少函數(shù)用于計(jì)算股票中的項(xiàng)目數(shù)和該股票的總價(jià)值 (其中使用設(shè)置格式 currencyStringFromNumber 方法定義在清單 4-12)汰聋。
在 ViewController.swift File 中使用元組

...
func displayStockTotal() {讓 finalTotals:(Int, Double) = products.reduce (0 (0.0),
        {(totals, product)-> (Int喊积,Double) in
            return (
                totals.0 + product.stockLevel烹困,totals.1 product.stockValue +
            );
        });
             totalStockLabel.text ="\(finalTotals.0) 在庫(kù)存中的產(chǎn)品"。
        +"總價(jià)值 ︰ \(Utils.currencyStringFromNumber(finalTotals.1))";
} ...

元組讓我產(chǎn)生兩個(gè)總計(jì)值 (一個(gè)用于股票中的項(xiàng)目數(shù))乾吻,一個(gè)為這支股票的價(jià)值為每次迭代中減少函數(shù)髓梅。能取得這以不同的方式 — — 如通過(guò)定義一個(gè)結(jié)構(gòu),具有兩個(gè)屬性绎签,或通過(guò)使用為循環(huán)來(lái)枚舉數(shù)組并更新兩個(gè)局部變量 — — 但使用元組與swift關(guān)閉很好地工作和生產(chǎn)是簡(jiǎn)單和易讀的代碼枯饿。這種使用,創(chuàng)建一個(gè)類或結(jié)構(gòu)將會(huì)矯枉過(guò)正诡必,因?yàn)橥饷娴姆椒ㄑ寄悖瑢?dǎo)出數(shù)據(jù),不是元組的下懷,不會(huì)引起出現(xiàn)傳遞更廣泛地在應(yīng)用程序中的元組時(shí)的緊耦合和維護(hù)問(wèn)題袱巨。
你可以看到額外的總數(shù)的效果我通過(guò)啟動(dòng)應(yīng)用程序來(lái)計(jì)算。該標(biāo)簽底部的布局將顯示的數(shù)量和項(xiàng)目?jī)r(jià)值的股票

摘要
在本章中碳抄,我描述了一種模式愉老,在swift發(fā)展的核心是 ︰ 定義一個(gè)用于創(chuàng)建對(duì)象的模板。這種模式的好處是剖效,它提供了基本的工具嫉入,可以用來(lái)打破緊耦合的組件分開(kāi),允許一個(gè)public API 來(lái)呈現(xiàn)給消費(fèi)者的一個(gè)對(duì)象和一個(gè)隱藏的私有實(shí)現(xiàn)璧尸。
在下一章咒林,我轉(zhuǎn)向創(chuàng)建對(duì)象的不同的方式 ︰ 使用原型.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市爷光,隨后出現(xiàn)的幾起案子垫竞,更是在濱河造成了極大的恐慌,老刑警劉巖蛀序,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欢瞪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡徐裸,警方通過(guò)查閱死者的電腦和手機(jī)遣鼓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)重贺,“玉大人骑祟,你說(shuō)我怎么就攤上這事∑希” “怎么了次企?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)健民。 經(jīng)常有香客問(wèn)我抒巢,道長(zhǎng),這世上最難降的妖魔是什么秉犹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任蛉谜,我火速辦了婚禮,結(jié)果婚禮上崇堵,老公的妹妹穿的比我還像新娘型诚。我一直安慰自己,他們只是感情好鸳劳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布狰贯。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪涵紊。 梳的紋絲不亂的頭發(fā)上傍妒,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音摸柄,去河邊找鬼颤练。 笑死,一個(gè)胖子當(dāng)著我的面吹牛驱负,可吹牛的內(nèi)容都是我干的嗦玖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼跃脊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼宇挫!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起酪术,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤器瘪,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后拼缝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體娱局,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年咧七,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了衰齐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡继阻,死狀恐怖耻涛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瘟檩,我是刑警寧澤抹缕,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站墨辛,受9級(jí)特大地震影響卓研,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜睹簇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一奏赘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧太惠,春花似錦磨淌、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)缚柳。三九已至,卻和暖如春搪锣,著一層夾襖步出監(jiān)牢的瞬間秋忙,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工构舟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留翰绊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓旁壮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親谐檀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子抡谐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)桐猬,斷路器麦撵,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件溃肪、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,103評(píng)論 4 62
  • 畢業(yè)答辯如期而至免胃,而我也正式終結(jié)了自己的學(xué)生生涯”棺回望前十八年羔沙,無(wú)數(shù)次守望這樣一個(gè)驚喜萬(wàn)分的時(shí)刻,今夜卻異常平靜厨钻。...
    striveto_beat閱讀 272評(píng)論 0 1
  • 那天去見(jiàn)了一起玩到大的好朋友扼雏,張張,聊來(lái)聊去聊到她轉(zhuǎn)正的男朋友夯膀,我很氣憤我在挑理诗充,哼為什么這么說(shuō),因?yàn)樗郧?..
    蕭穎閱讀 139評(píng)論 2 1
  • 大家知道SKT的打法嗎? 完美俺猿,滴水不漏茎匠,運(yùn)籌帷幄。 他們最強(qiáng)的是辜荠,讓敵人慢性死亡汽抚。 他們幾乎不出錯(cuò)的自己打自己的...
    黃銅刀閱讀 312評(píng)論 0 0