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)避免成為大量的重寫伏筆,松散耦合的組件在設(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)是你寫在開(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ò)重寫的一個(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ù)類型定義在相同的地方?,F(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)單的。在編寫代碼清單 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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,618評(píng)論 19 139
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,422評(píng)論 4 61
  • 畢業(yè)答辯如期而至,而我也正式終結(jié)了自己的學(xué)生生涯。回望前十八年,無(wú)數(shù)次守望這樣一個(gè)驚喜萬(wàn)分的時(shí)刻,今夜卻異常平靜。...
    striveto_beat閱讀 315評(píng)論 0 1
  • 那天去見(jiàn)了一起玩到大的好朋友,張張,聊來(lái)聊去聊到她轉(zhuǎn)正的男朋友,我很氣憤我在挑理,哼為什么這么說(shuō),因?yàn)樗郧?..
    蕭穎閱讀 171評(píng)論 2 1
  • 為什么微信底部導(dǎo)航按鈕只有4個(gè)?按鈕之間的間距是如何設(shè)計(jì)的? 查閱相關(guān)資料得知,底部導(dǎo)航按鈕的設(shè)計(jì)原則是3-5個(gè)。...
    851b667e724d閱讀 1,181評(píng)論 0 1

友情鏈接更多精彩內(nèi)容