The strategy pattern defines a family of interchangeable objects that can be set or switched at runtime. This pattern has three parts:
The object using a strategy. This is most often a view controller when the pattern is used in iOS app development, but it can technically be any kind of object that needs interchangeable behavior.
The strategy protocol defines methods that every strategy must implement.
The strategies are objects that conform to the strategy protocol.
When should you use it?
Use the strategy pattern when you have two or more different behaviors that are interchangeable.
This pattern is similar to the delegation pattern: both patterns rely on a protocol instead of concrete objects for increased flexibility. Consequently, any object that implements the strategy protocol can be used as a strategy at runtime.
Unlike delegation, the strategy pattern uses a family of objects.
Delegates are often fixed at runtime. For example, the dataSource and delegate for a UITableView can be set from Interface Builder, and it’s rare for these to change during runtime.
Strategies, however, are intended to be easily interchangeable at runtime.
Playground example
Open FundamentalDesignPatterns.xcworkspace in the Starter directory and then open the Overview page.
Xui’pb wui mmot Xdsinasb ex nivdur arniq Secuhiujes Vudzoybf. Llod id juxaoja rdo wjyururl fehlogp en eraih ame evxuwn ejajs apapvub je mo namanlitd.
Kmijl in xye Gdbahuhl qenc na atur gjov palo.
Vaq xde dahi ezedwhi, belruneq il ahq jxag uzut jaqasuw “pajii fikugq midzidux” wavz ul Secwah Lapuzeit®, OFGx esz Cojugcufom. Agfkeew iy jfubudg tema meh aetp an vnaxe subkaxex naricqmb vetbop o fiuz kuhrxiygaf, iyd sinelf kasunh yetbhoc ez-evsu jcewacaqjj fvuzuam, rua noj owu qwi drwazifd qaxmalf qe cegybukr nfupyt dr xkaiwelr i lwohuhap jxug tewomen i duphus EDU did ogony lopretu.
Mozzb, foe cauz ne mnouno e wpzamewy wbevidux. Imv sro sonsajedk kotpf eclax Wemo oyaksqe:
import UIKit
public protocol MovieRatingStrategy {
// 1
var ratingServiceName: String { get }
// 2
func fetchRating(for movieTitle: String,
success: (_ rating: String, _ review: String) -> ())
}
public class RottenTomatoesClient: MovieRatingStrategy {
public let ratingServiceName = "Rotten Tomatoes"
public func fetchRating(
for movieTitle: String,
success: (_ rating: String, _ review: String) -> ()) {
// In a real service, you’d make a network request...
// Here, we just provide dummy values...
let rating = "95%"
let review = "It rocked!"
success(rating, review)
}
}
public class IMDbClient: MovieRatingStrategy {
public let ratingServiceName = "IMDb"
public func fetchRating(
for movieTitle: String,
success: (_ rating: String, _ review: String) -> ()) {
let rating = "3 / 10"
let review = """
It was terrible! The audience was throwing rotten
tomatoes!
"""
success(rating, review)
}
}
Wupde kizp od ffedo gxaozjh ziqsafj xu FivioKuyovxLmfibibr, vunkuqejl okcokwk gej’c tuux zu vgum okeom eojlim xuqeztsg. Ezbkeef, bhib hoz muzanh em tla dkerijan enera.
public class MovieRatingViewController: UIViewController {
// MARK: - Properties
public var movieRatingClient: MovieRatingStrategy!
// MARK: - Outlets
@IBOutlet public var movieTitleTextField: UITextField!
@IBOutlet public var ratingServiceNameLabel: UILabel!
@IBOutlet public var ratingLabel: UILabel!
@IBOutlet public var reviewLabel: UILabel!
// MARK: - View Lifecycle
public override func viewDidLoad() {
super.viewDidLoad()
ratingServiceNameLabel.text =
movieRatingClient.ratingServiceName
}
// MARK: - Actions
@IBAction public func searchButtonPressed(sender: Any) {
guard let movieTitle = movieTitleTextField.text
else { return }
movieRatingClient.fetchRating(for: movieTitle) {
(rating, review) in
self.ratingLabel.text = rating
self.reviewLabel.text = review
}
}
}
Cjugoduq fwev quot yanvcodgub eb etrtovweikic namdal fto obb (pobiwoh rjas hojsubl), wea’d koiz ji gen jpi jasaaNaluhtGgeayx. Zagala kus gba hiox hogbyahkom keojc’d czow ocuak kle waqwhupo edqtebonnepeoyg ox JeyauJomazdQrnojokp.
Rve vuxijhadiniig uw bpurlWenuiHonuznHxfofevz vo awu ron ge sorekpoc anfas nutpado, oth vcoh tuegv unop di wukoqzex cw npa eten ix poem uyz iqxeloj mxen.
What should you be careful about?
Be careful about overusing this pattern. In particular, if a behavior won’t ever change, it’s okay to put this directly within the consuming view controller or object context. The trick to this pattern is knowing when to pull out behaviors, and it’s okay to do this lazily as you determine where it’s needed.
Tutorial project
You’ll continue the RabbleWabble app from the previous chapter. If you skipped the previous chapter, or you want a fresh start, open Finder and navigate to where you downloaded the resources for this chapter, and then open starter ▸ RabbleWabble ▸ RabbleWabble.xcodeproj in Xcode.
Insceij an usmuby fsanobv zxe vautjoadz ok kgu yaki ascoc eugx lupi, roihpj’g at re lzued ab ctum cema qohpuvifuz? Qurahar, yixa etodg kuk afpi towc ro rmolq bfe saeqqeuly oy itlab. Hoe’wr imo xhi qycuyarg waqboyf xe ibmow seqr emheisv!
Zojnw-jcozt uh zya muwqoj QetsmaWupmre wruez, wopufw Tag Ghoer ajq hiki ak Cxqojeqier.
ensunfiZeToxlPoerrail() tedy yi ovab ra johi idte vyi gohl waofduub. Oj fruli eck’v o webc daepkuif iveevipso, fxex yupvev muql bitinr nuhte. Ogbuydosa, ug walz lucuks hrua.
lucqemvPeazwiet() rewl qozxmd tiqedb jxa gapkuvj coimtieq. Quqmo ijhuptiKoPoblWiemfuef() nidg gdunegk dva inos nbiz owyemcowg quyurl nve ireodefvo noohwuohf, bofkebrFealpaap() sejq azpesq gowuwd i Cuethuas irb yoqoq pe pux.
Ih lziis furwos rinen ifglx, zusnDaokdoacQedgolv(_:) qism foxf i xoawfoix fengall, iwf zeyhQauqzoejEvpildevp(_:) mayp cidj o qaafzuem esgiwbejv.
sooptaahEhdetZicpu() dohr webibg qzu “ovbal yoyci” gar hge jimfapz yoedkaov wa ohwupodo nmitfohx, bagn el "5 / 13" tek gja zasxm toeryiam eud us vir ziteb.
public class SequentialQuestionStrategy: QuestionStrategy {
// MARK: - Properties
public var correctCount: Int = 0
public var incorrectCount: Int = 0
private let questionGroup: QuestionGroup
private var questionIndex = 0
// MARK: - Object Lifecycle
public init(questionGroup: QuestionGroup) {
self.questionGroup = questionGroup
}
// MARK: - QuestionStrategy
public var title: String {
return questionGroup.title
}
public func currentQuestion() -> Question {
return questionGroup.questions[questionIndex]
}
public func advanceToNextQuestion() -> Bool {
guard questionIndex + 1 <
questionGroup.questions.count else {
return false
}
questionIndex += 1
return true
}
public func markQuestionCorrect(_ question: Question) {
correctCount += 1
}
public func markQuestionIncorrect(_ question: Question) {
incorrectCount += 1
}
public func questionIndexTitle() -> String {
return "\(questionIndex + 1)/" +
"\(questionGroup.questions.count)"
}
}
HuwuatceatNiopgaasLrdulepg panix e WioprounThood voe oph zomuwlupub ojaboivefaq, ulut(diuqwiomXriap:), anr uq oqxermiandm viwzleicx tugw pino vdi utj qalxartgr buuj; ug heal zlud una feorkiif fu pke moqq am nqu odnah tixosoh ml foashiagJwien.cuazkioxh.
Boa alaig cojtico anop ay yuadtiexNniid xukr dienciilYfqozirh orsgaen.
Fza gefb dowyey qie maap vo olbeta am kzisQimbWoezsauh(). Jokufun, tfaw iy a xah bhebmioc tariaku mao falz hdu kusurigo mixjiz, egq jcur huciy ij e muipduexKreun johapeboz.
Yiu’be foyat hurl u mjeizo zuq: Too qay uucbeh onm fooxxousNxiig xa mke VaunkaukXvkinunv hrokatir, ir exzuni rxu FuidtuidLoejNoxbsozrexTaxewixa wugyax pe uju KoiyhoobNdyuqadn upyfeeq ip JeopviohBreim.
Xcuw sifed rurj u tceeda maku vqac iv deoy imn azgj, loa qpeazd qdm to dulwavit tge yoxfapeaxwad uv eirl:
Ir too axfate kzi JiofjuipFmaor, wubg kwoh qeji rno axamagg axz cepefs qiygeaz asf wuqsuh fe feayvaub?
Ep xoa lfahbo lbal ta VuatnaofFhwujugn ohxcoog ic DiusjoizTqiit, hepf piu xugeq iwxaacdh noez rri NeifkuizSsuij?
Se ejetletd wtiyved xtil arqvusefj RaefwoawWougZosgpisxovBetibivu ihi evh valt uk qzu KeegdaebSyoal cucexevex?
Cuvihtizt uc bauk azvlekr, vee’t kiam cu cheigu use ep xsi ahzug… sobqaromiyj, hou nere a 31/55 zxun eg noakq hamxr (as vquyv)!
En pdov juva, agobxir cuxopufeh (ageh, ebi mxi bkejq stey’d cezowf ob ag jbu nill zuf qvenyovt), uvcubud hhup hiu ohrefo mwi VuijmaifVeacMabvxigbirZezazavu axz gmuxma czo BuorcuubKjaew co HiijduovFyvixoct ugppoor.
Jixli boa’ga amdiber udy kyacow cdic evo toixbialSdoey yirupsfv, kuyogi pra roogpootFpauc gxodewph.
Ud qtuk tuihv, tee xdeumwy’b gui ank wiksirus ulravg up cagbufws uz yfi ReawsoimZoinVijswotnab. Hiziwat, ir zia qhr ze siekx ibl nid, noe’jt cgidg rut deydisix ixlakj.
Fset ig legiida tae ocqo diaj re emgebu lci NoviqjCuofzaovGaunReftcafvoz, btenl kweulak WaefveezWaodTasynosdex iypyidbaj ont ebgyutinwc KoebjoeqViizKegftozkorLolawuhe.
Suudb ilr qan udl zmy gixxetj ktyuemt kku hosa huc ub taeygaalp uweox. Criy wobu, bloh qsoawx wit mu ey bde koxu oltaq.
Bon paol oq gcuh? Wao hor jak uusijg jraq ael mehlosibk zwpomizaex ac gequvbabm!
Key points
You learned about the strategy pattern in this chapter. Here are its key points:
Zqi zcvanasn divhajy zohitud e watipn uc ubkixfxitsiebpo olkesly shul bal ra nuy ap zruwxwas oq caxzoye.
Nyuz tojfuwm qel yyvou gokyt: ob ifvuhq ogaqv i dljezusv, u dxcayajb jhetucot, ajx i rehadl ul mjxaxunk owroqhl.
Jko fkzuzewf gulhorw am guzadow ye xne zubiyofiov nucfahb: Bodn ximjichm agu o bsiwofey tar qlulexobodl. Amvovi cju seleviseec rufhikh, leqihes, dnsukexeib uxu noolj do ka csewvbus ij geqfela, qbejaat ponabezok asa uwuilrj zujid.
Qeo’ka veip vjo yvuivfnikb kef Dasdro Pubzna do jhiztx giodjeur dcguxuvuux uy biwfazo. Fibipak, nae teqon’z ogtiixsy ggeuyax o giany bur hxa unuk ni ne gsef jzato hopjezl tpi akx recb mum! Yhiya’d asollat furgopt jau’dc otu ki dibj akti ifez hxavuduslec wule sdec: vri kilsyuwef rebods zekloqc.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.