第四周第一天
協(xié)議,協(xié)議的語法
protocol Flyable {
func fly()
}
protocol Fightable {
func fight()
}
協(xié)議是方法的集合(計算屬性相當(dāng)于就是方法)
// 可以把看似不相關(guān)的對象的公共行為放到一個協(xié)議中
// 協(xié)議在Swift開發(fā)中大致有三種作用:
// 1. 能力 - 遵循了協(xié)議就意味著具備了某種能力
// 2. 約定 - 遵循了協(xié)議就一定要實(shí)現(xiàn)協(xié)議中的方法
// 3. 角色 - 一個類可以遵循多個協(xié)議, 一個協(xié)議可以被多個類遵循, 遵循協(xié)議就意味著扮演了某種角色, 遵循多個協(xié)議就意味著可以扮演多種角色
// Swift中的繼承是單一繼承(一個類只能有一個父類), 如果希望讓一個類具備多重能力可以使用協(xié)議來實(shí)現(xiàn)(C++里面是通過多重繼承來實(shí)現(xiàn)的, 這是一種非常狗血的做法)
協(xié)議的繼承
class Boxer: Fightable {
@objc func fight() {
print("正在進(jìn)行格斗.")
}
}
class Bird: Flyable {
func fly() {
print("鳥兒扇動翅膀飛行.")
}
}
class Airplane: Flyable {
func fly() {
print("飛機(jī)依靠空氣動力學(xué)原理飛行.")
}
}
協(xié)議的拓展也可以說協(xié)議的默認(rèn)實(shí)現(xiàn)當(dāng)在類中沒有實(shí)現(xiàn)這個方法默認(rèn)實(shí)現(xiàn)的方法
協(xié)議擴(kuò)展 - 可以在協(xié)議擴(kuò)展中給協(xié)議中的方法提供默認(rèn)實(shí)現(xiàn)
也就是說如果某個類遵循了協(xié)議但是沒有實(shí)現(xiàn)這個方法就直接使用默認(rèn)實(shí)現(xiàn)
那么這個方法也就相當(dāng)于是一個可選方法(可以實(shí)現(xiàn)也可以不實(shí)現(xiàn))
extension Fightable {
func fight() {
print("正在打架")
}
}
依賴倒轉(zhuǎn)原則(面向協(xié)議編程)
- 聲明變量的類型時應(yīng)該盡可能使用協(xié)議類型
- 聲明方法參數(shù)類型時應(yīng)該盡可能使用協(xié)議類型
- 聲明方法返回類型時應(yīng)該盡可能使用協(xié)議類型
協(xié)議的組合
let array: [protocol<Flyable, Fightable>] = [
// Rocket(),
// Bird(),
Superman(),
// Boxer()
// Airplane()
]
//只有同時滿足兩個協(xié)議的類才可以
for obj in array {
obj.fly()
obj.fight()
}
協(xié)議中全是抽象概念(只有聲明沒有實(shí)現(xiàn)) 遵循協(xié)議的類可以各自對協(xié)議中的計算屬性和方法給出自己的實(shí)現(xiàn)版本 這樣當(dāng)我們面向協(xié)議編程時就可以把多態(tài)的優(yōu)勢發(fā)揮到淋漓盡致 可以寫出更通用更靈活的代碼(符合開閉原則)
實(shí)現(xiàn)開閉原則最關(guān)鍵有兩點(diǎn):
- 抽象是關(guān)鍵(在設(shè)計系統(tǒng)的時候一定要設(shè)計好的協(xié)議);
- 封裝可變性(橋梁模式 - 將不同的可變因素封裝到不同的繼承結(jié)構(gòu)中)
接口(協(xié)議)隔離原則: 協(xié)議的設(shè)計要小而專不要大而全
協(xié)議的設(shè)計也要高度內(nèi)聚
protocol Shape {
var perimeter: Double { get }
var area: Double { get }
func draw()
}
class Triangle: Shape {
var a: Double
var b: Double
var c: Double
init(a: Double, b: Double, c: Double) {
assert(a + b > c && b + c > a && a + c > b, "不能構(gòu)成三角形")
self.a = a
self.b = b
self.c = c
}
var perimeter: Double {
get { return a + b + c }
}
var area: Double {
get {
let half = perimeter / 2
return sqrt(half * (half - a) * (half - b) * (half - c))
}
}
func draw() {
print("△")
}
}
協(xié)議的應(yīng)用
#### //圖書類的定義
import Foundation
/// 圖書
class Book {
var name: String
var price: Double
var type: String
// 四人幫設(shè)計模式 - 策略模式
var strategy: DiscountStrategy?
/**
初始化方法
- parameter name: 書名
- parameter price: 價格
- parameter type: 類型
*/
init(name: String, price: Double, type: String) {
self.name = name
self.price = price
self.type = type
}
/// 減多少錢
var discountValue: Double {
get {
if let s = strategy {
return s.discount(price)
}
else {
return 0
}
}
}
/// 折后價格
var discountedPrice: Double {
get { return price - discountValue }
}
}
#### //寫協(xié)議部分
import Foundation
/**
* 打折策略協(xié)議
*/
protocol DiscountStrategy {
/**
計算折扣
- parameter price: 原價
- returns: 折扣的金額
*/
func discount(price: Double) -> Double
}
/// 百分比折扣策略
class PercentageDiscount: DiscountStrategy {
var percentage: Double
init(percentage: Double) {
self.percentage = percentage
}
func discount(price: Double) -> Double {
return price * (1 - percentage)
}
}
// 固定金額折扣策略
class FixedDiscount: DiscountStrategy {
var fixedMoney: Double
init(fixedMoney: Double) {
self.fixedMoney = fixedMoney
}
func discount(price: Double) -> Double {
return price >= fixedMoney ? fixedMoney : 0
}
}
// 分段折后策略
class SegmentedDiscount: DiscountStrategy {
func discount(price: Double) -> Double {
if price < 20 {
return 0
}
else if price < 50 {
return 3
}
else if price < 100 {
return 10
}
else {
return 30
}
}
}
#### //實(shí)現(xiàn)和調(diào)用部分
import Foundation
let booksArray = [
Book(name: "C語言程序設(shè)計", price: 24.0, type: "計算機(jī)"),
Book(name: "名偵探柯南", price: 98.5, type: "漫畫"),
Book(name: "Swift從入門到住院", price: 35.8, type: "計算機(jī)"),
Book(name: "黃岡數(shù)學(xué)密卷", price: 34.2, type: "教材"),
Book(name: "中國股市探秘", price: 58.5, type: "金融")
]
let discountDict: [String: DiscountStrategy] = [
"計算機(jī)": PercentageDiscount(percentage: 0.78),
"教材": PercentageDiscount(percentage: 0.85),
"漫畫": SegmentedDiscount(),
"科普": FixedDiscount(fixedMoney: 2)
]
var totalPrice = 0.0
var totalDiscount = 0.0
for book in booksArray {
if let strategy = discountDict[book.type] {
book.strategy = strategy
}
print("《\(book.name)》原價: ¥\(book.price)元")
print("《\(book.name)》折后價: ¥\(book.discountedPrice)元")
totalPrice += book.discountedPrice
totalDiscount += book.discountValue
}
print(String(format: "總計: ¥%.1f元", totalPrice))
print(String(format: "為您節(jié)省了: ¥%.1f元", totalDiscount))