下面簡單的介紹面向協議的編程的應用
擴展協議和默認實現
面向協議編程
協議聚合
泛型約束
swift是面向協議的編程語言
UIKit中的委托模式
創建自己的委托模式
可選的協議方法
protocol Record: CustomStringConvertible{
var wins: Int {get}
var losses: Int {get}
func winningPercent() -> Double
}
// 擴展一個協議的時候,可以擁有實現!,那麼就是說,雖然協議不能夠實現屬性和方法,但是在協議的擴展裡面可以實現屬性和方法
extension Record{
//那麼遵守CustomStringConvertible協議必須實現的屬性就可以寫在協議的擴展裡面,那麼結構體和類中就可以不寫,打印出來的結果就是自定義的格式
//這個例子就是告訴我們,在協議的擴展中,可以實現屬性和函數的邏輯,在類和結構中就不需要實現了
var description: String{
return String(format: "WINS: %d , LOSSES: %d", arguments: [wins,losses])
}
func shoutWins(){
print("WE WIN",wins,"TIMES!!!")
}
var gamePlayed: Int{
return wins + losses
}
}
struct BasketballRecord: Record{
var wins: Int
var losses: Int
func winningPercent() -> Double {
//return Double(wins)/Double(wins + losses)
return Double(wins)/Double(gamePlayed)
}
}
//extension BasketballRecord: CustomStringConvertible{}
struct BaseballRecord: Record{
var wins: Int
var losses: Int
func winningPercent() -> Double {
return Double(wins)/Double(gamePlayed)
}
}
let teamRecord = BasketballRecord(wins: 2, losses: 10)
print(teamRecord)
teamRecord.shoutWins()
// 擴展標准庫中的協議
extension CustomStringConvertible{
var descriptionWithDate: String{
return NSDate().description + " " + description
}
}
print( teamRecord.descriptionWithDate )
protocol Record: CustomStringConvertible{
var wins: Int {get}
var losses: Int {get}
//func winningPercent() -> Double
}
extension Record{
var description: String{
return String(format: "WINS: %d , LOSSES: %d", arguments: [wins,losses])
}
var gamePlayed: Int{
return wins + losses
}
}
protocol Tieable{
var ties: Int{get set}
}
//由於有些比賽沒有平局,那麼我只想給有平局的結構和類增加一個協議的擴張,用where關鍵字,表示如果這個類或者結構遵守了Tieable協議的話,我就給他擴展這個平局的屬性,然後再將gamePlayed和winningPercent的實施細則重寫,覆蓋在協議中默認的內容,那麼如果,我們類或結構遵守了Tieable這個協議的話,我們就可以直接使用這個被覆蓋的gamePlayed屬性和winningPercent方法了
extension Record where Self: Tieable{
var gamePlayed: Int{
return wins + losses + ties
}
func winningPercent() -> Double {
return Double(wins)/Double(wins + losses + ties)
}
}
struct BasketballRecord: Record{
var wins: Int
var losses: Int
// func winningPercent() -> Double {
// return Double(wins)/Double(gamePlayed)
// }
}
//由於在Record協議裡面有一個默認的gamePlayed屬性實現過程,但是在我們的具體的結構和類中,可以重寫這個屬性的實現,也就是可以覆蓋協議擴展中屬性的實現過程
struct BaseballRecord: Record{
var wins: Int
var losses: Int
let gamePlayed = 162
// func winningPercent() -> Double {
// return Double(wins)/Double(gamePlayed)
// }
}
struct FootballRecord: Record, Tieable{
var wins: Int
var losses: Int
var ties: Int
// var gamePlayed: Int{
// return wins + losses + ties
// }
//
// func winningPercent() -> Double {
// return Double(wins)/Double(wins+losses+ties)
// }
}
let basketballTeamRecord = BasketballRecord(wins: 2, losses: 10)
let baseballTeamRecord = BaseballRecord(wins: 10, losses: 5)
basketballTeamRecord.gamePlayed
baseballTeamRecord.gamePlayed
let footballTeamRecord = FootballRecord(wins: 1, losses: 1, ties: 1)
footballTeamRecord.gamePlayed
footballTeamRecord.winningPercent()
protocol Record: CustomStringConvertible{
var wins: Int {get}
var losses: Int {get}
}
extension Record{
var description: String{
return String(format: "WINS: %d , LOSSES: %d", arguments: [wins,losses])
}
var gamePlayed: Int{
return wins + losses
}
func winningPercent() -> Double {
return Double(wins)/Double(gamePlayed)
}
}
protocol Tieable {
var ties: Int {get set}
}
extension Record where Self: Tieable{
var gamePlayed: Int{
return wins + losses + ties
}
func winningPercent() -> Double {
return Double(wins)/Double(wins + losses + ties)
}
}
protocol Prizable{
func isPrizable() -> Bool
}
struct BasketballRecord: Record, Prizable{
var wins: Int
var losses: Int
func isPrizable() -> Bool{
return wins > 2
}
}
struct BaseballRecord: Record, Prizable{
var wins: Int
var losses: Int
let gamePlayed = 162
func isPrizable() -> Bool{
return gamePlayed > 10 && winningPercent() >= 0.5
}
}
struct FootballRecord: Record, Tieable, Prizable{
var wins: Int
var losses: Int
var ties: Int
func isPrizable() -> Bool{
return wins > 1
}
}
var basketballTeamRecord = BasketballRecord(wins: 2, losses: 10)
var baseballTeamRecord = BaseballRecord(wins: 10, losses: 5)
var footballTeamRecord = FootballRecord(wins: 1, losses: 1, ties: 1)
//這裡表面傳遞進來的one不僅要遵守Prizable協議還要遵守CustomStringConvertible協議
func award(one: protocol){
if one.isPrizable(){
print(one)
print("Congratulation! You won a prize!")
}
else{
print(one)
print("You can not have the prize!")
}
}
award(baseballTeamRecord)
struct Student: CustomStringConvertible, Prizable{//description是CustomStringConvertible必須實現的屬性
var name: String
var score: Int
var description: String{
return name
}
func isPrizable() -> Bool {
return score >= 60
}
}
let liuyubobobo = Student(name: "liuyubobobo", score: 100)
award(liuyubobobo)
protocol Prizable{
func isPrizable() -> Bool
}
struct Student: CustomStringConvertible, Equatable, Comparable, Prizable{
var name: String
var score: Int
var description: String{
return name + "Score: " + String(score)
}
func isPrizable() -> Bool {
return score >= 60
}
}
func ==(s1:Student,s2:Student) -> Bool{ return s1.score == s2.score}
func <(s1:Student,s2:Student) -> Bool{ return s1.score < s2.score}
let liuyubobobo = Student(name: "liuyubobobo", score: 100)
let a = Student(name: "Alice", score: 80)
let b = Student(name: "Bob", score: 92)
let c = Student(name: "Karl", score: 85)
let students = [a, b, c, liuyubobobo]
//func topOne(seq:[Comparable]) -> Comparable
//讓大寫的遵守Comparable協議,讓數組元素的類型為T,就是泛型的約束,,
func topOne(seq:[T]) -> T{
assert(seq.count > 0)
//如果使數組中的元素壓縮成一個元素,使用結尾閉包
return seq.reduce(seq[0]){ max( $0 , $1 ) }
}
topOne([4,5,7,2])
topOne(["Hello","Swift"])
topOne([a,b,c,liuyubobobo])
//讓大寫的遵守Comparable協議,讓數組元素的類型為T,>就是協議聚合的泛型約束,,
func topPrizableOne>(seq:[T]) -> T?{
return seq.reduce(nil){ ( tmpTop: T? , contender: T) in
guard contender.isPrizable() else{
return tmpTop
}
guard let tmpTop = tmpTop else{
return contender
}
return max( tmpTop , contender )
}
}
topPrizableOne(students)?.name
/**
根據swift語言中標准庫的統計:
Classes: 6 個
Enum: 8 個
Structs: 103 個
Protocol: 86 個
*/
var a: Int = 3
var arr: Array = [1,2,3]
這個例子用uitableview引出
protocol TurnBasedGameDelegate{
func gameStart()
func playerMove()
func gameEnd()
func gameOver() -> Bool
}
protocol TurnBasedGame{
var turn: Int{get set}
func play()
}
//這個類完成了整個游戲的過程,但是不知道游戲的細節部分,那麼在具體的玩這個游戲的時候,我們就不要擔心這個游戲到底是怎麼一個過程,只是說明這個游戲怎麼玩就是了
class SinglePlayerTurnBasedGame: TurnBasedGame{
var delegate:TurnBasedGameDelegate!
var turn = 0
func play(){
delegate.gameStart()//游戲開始
while !delegate.gameOver() {//知道什麼時候結束
print("ROUND",turn,":")
delegate.playerMove()//玩家開始動作
turn += 1
}
delegate.gameEnd()
}
}
class RollNumberGame: SinglePlayerTurnBasedGame, TurnBasedGameDelegate{
var score = 0
override init() {
super.init()//先調用父類的構造函數,初始化父類的屬性
delegate = self//再初始化自己屬性
}
func gameStart() {
score = 0
turn = 0
print("Welcome to Roll Number Game.")
print("Try to use least turn to make total 100 scores!")
}
func playerMove() {
let rollNumber = Int(arc4random())%6 + 1
score += rollNumber
print("You rolled a" , rollNumber , "! The score is",score,"now!")
}
func gameEnd() {
print("Congratulation! You win the game in" , turn , "ROUND!")
}
func gameOver() -> Bool{
return score >= 30
}
}
let rollingNumber = RollNumberGame()
rollingNumber.play()
class RockPaperScissors: SinglePlayerTurnBasedGame, TurnBasedGameDelegate{
enum Shape: Int, CustomStringConvertible{
case Rock
case Scissors
case Papper
func beat(shape: Shape) -> Bool{
return (self.rawValue + 1)%3 == shape.rawValue
}
var description: String{
switch(self){
case .Papper: return "Paper"
case .Rock: return "Rock"
case .Scissors: return "Scissors"
}
}
}
var wins = 0
var otherWins = 0
override init() {
super.init()
delegate = self
}
static func go() -> Shape{
return Shape(rawValue: Int(arc4random())%3)!
}
func gameStart() {
wins = 0
otherWins = 0
print("== Rock Paper Scissor ==")
}
func gameOver() -> Bool {
//return turn >= 3
return wins >= 2 || otherWins >= 2
}
func gameEnd() {
if( wins >= 2 ){
print("YOU WIN!")
}
else{
print("YOU LOSE...")
}
}
func playerMove() {
let yourShape = RockPaperScissors.go()
let otherShape = RockPaperScissors.go()
print("Your:",yourShape)
print("Other:",otherShape)
if yourShape.beat(otherShape){
print("You win this round")
wins += 1
}
else if otherShape.beat(yourShape){
print("You lose this round")
otherWins += 1
}
else{
print("Tie in this round")
}
}
}
let rockPaperScissors = RockPaperScissors()
rockPaperScissors.play()
//如果協議中有可選型的方法,那麼在協議前必須加上@objc關鍵字,那麼這個協議就能被OC語言應用
@objc protocol TurnBasedGameDelegate{
func gameStart()
func playerMove()
func gameEnd()
optional func turnStart()
optional func turnEnd()
func gameOver() -> Bool
}
protocol TurnBasedGame{
var turn: Int{get set}
func play()
}
//那麼這個父類也要繼承object-c
class SinglePlayerTurnBasedGame: NSObject, TurnBasedGame{
var delegate:TurnBasedGameDelegate!
var turn = 0
func play(){
delegate.gameStart()
while !delegate.gameOver() {
//如果一個函數是可選型的函數,那麼這個函數就要解包
if let turnStart = delegate.turnStart{
turnStart()
}
else{
print("Round",turn,":")
}
delegate.playerMove()
//這裡也需要解包,如果解包成功了就調用這個函數,如果解包失敗就什麼事也不做
delegate.turnEnd?()
turn += 1
}
delegate.gameEnd()
}
}
class RockPaperScissors: SinglePlayerTurnBasedGame, TurnBasedGameDelegate{
enum Shape: Int, CustomStringConvertible{
case Rock
case Scissors
case Papper
func beat(shape: Shape) -> Bool{
return (self.rawValue + 1)%3 == shape.rawValue
}
var description: String{
switch(self){
case .Papper: return "Paper"
case .Rock: return "Rock"
case .Scissors: return "Scissors"
}
}
}
var wins = 0
var otherWins = 0
override init() {
super.init()
delegate = self
}
static func go() -> Shape{
return Shape(rawValue: Int(arc4random())%3)!
}
@objc func gameStart() {//
wins = 0
otherWins = 0
print("== Rock Paper Scissor ==")
}
func gameOver() -> Bool {
return wins >= 2 || otherWins >= 2
}
func gameEnd() {
if( wins >= 2 ){
print("YOU WIN!")
}
else{
print("YOU LOSE...")
}
}
func playerMove() {
let yourShape = RockPaperScissors.go()
let otherShape = RockPaperScissors.go()
print("Your:",yourShape)
print("Other:",otherShape)
if yourShape.beat(otherShape){
print("You win this round")
wins += 1
}
else if otherShape.beat(yourShape){
print("You lose this round")
otherWins += 1
}
else{
print("Tie in this round")
}
}
func turnStart() {
print("*** ROUND START ***")
}
func turnEnd(){
print("*******************")
}
}
let rockPaperScissors = RockPaperScissors()
rockPaperScissors.play()