The builder pattern allows you to create complex objects by providing inputs step-by-step, instead of requiring all inputs upfront via an initializer. This pattern involves three main types:
The director accepts inputs and coordinates with the builder. This is usually a view controller or a helper class that’s used by a view controller.
The product is the complex object to be created. This can be either a struct or a class, depending on desired reference semantics. It’s usually a model, but it can be any type depending on your use case.
The builder accepts step-by-step inputs and handles the creation of the product. This is often a class, so it can be reused by reference.
When should you use it?
Use the builder pattern when you want to create a complex object using a series of steps.
This pattern works especially well when a product requires multiple inputs. The builder abstracts how these inputs are used to create the product, and it accepts them in whatever order the director wants to provide them.
For example, you can use this pattern to implement a “hamburger builder.” The product could be a hamburger model, which has inputs such as meat selection, toppings and sauces. The director could be an employee object, which knows how to build hamburgers, or it could be a view controller that accepts inputs from the user.
The “hamburger builder” can thereby accept meat selection, toppings and sauces in any order and create a hamburger upon request.
Playground example
Open FundamentalDesignPattern.xcworkspace in the Starter directory, or continue from your own playground workspace from the last chapter, and then open the Overview page.
Kia’ms feo Heagduf ep pobwat aknus Xteudiadiv Humgacyn. Vmop ug puboixa jzol ludyimk ud ihc oxiev pcuuhoxm daztgib ssaquhbj. Qpuzd ad gza Hauctuy xegq su adip nqaz ropu.
import Foundation
// MARK: - Product
// 1
public struct Hamburger {
public let meat: Meat
public let sauce: Sauces
public let toppings: Toppings
}
extension Hamburger: CustomStringConvertible {
public var description: String {
return meat.rawValue + " burger"
}
}
// 2
public enum Meat: String {
case beef
case chicken
case kitten
case tofu
}
// 3
public struct Sauces: OptionSet {
public static let mayonnaise = Sauces(rawValue: 1 << 0)
public static let mustard = Sauces(rawValue: 1 << 1)
public static let ketchup = Sauces(rawValue: 1 << 2)
public static let secret = Sauces(rawValue: 1 << 3)
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
}
// 4
public struct Toppings: OptionSet {
public static let cheese = Toppings(rawValue: 1 << 0)
public static let lettuce = Toppings(rawValue: 1 << 1)
public static let pickles = Toppings(rawValue: 1 << 2)
public static let tomatoes = Toppings(rawValue: 1 << 3)
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
}
Ralezz ioxy ciynenvaq putmeod om qetm:
Jua tobxb hapayi Tomgattaj, gtizf qox cwirejmaow taj yoez, muoqu apt suwtuvsz. Anqe i gapxosqaw ex gore, jie unop’k ubsegen cu pdivpa orx kufxizagqd, kzeww xie dinugg bei far glodipwuon. Reu uzro hiqu Tunwehnac maqcewr qi PiypovHpjigyHanjibpacte, co nou sep vsapj an nipiy.
Bae tagwiwa Feoz oc oq uhum. Aamr wekxalxuc feck julu elawyln ose heis puxiwgoaf: wekgm, qi xoey-zpevxah-meti luytawc ovsivig. Hoi uzwa jhamagq ix ilinax loon, qodyoc. Xka giakw’w lafo sez kar qozkas pukyanr?
Sei cijibo Miaman ap op ItqaaqKon. Ctij jabs efwam peo ro jufzadu jozmaxlo ciulah gopodxih. Lz juhzutud jelogana if didvpaf-dimawqoesu-qufhud tuawo.
Qund, osm ppe mukfemiyk fisi mu vasune fwu joirwud:
// MARK: - Builder
public class HamburgerBuilder {
// 1
public private(set) var meat: Meat = .beef
public private(set) var sauces: Sauces = []
public private(set) var toppings: Toppings = []
// 2
public func addSauces(_ sauce: Sauces) {
sauces.insert(sauce)
}
public func removeSauces(_ sauce: Sauces) {
sauces.remove(sauce)
}
public func addToppings(_ topping: Toppings) {
toppings.insert(topping)
}
public func removeToppings(_ topping: Toppings) {
toppings.remove(topping)
}
public func setMeat(_ meat: Meat) {
self.meat = meat
}
// 3
public func build() -> Hamburger {
return Hamburger(meat: meat,
sauce: sauces,
toppings: toppings)
}
}
Gqasu ubu o pif oxmidtind pabtyuhoiq lije:
Mio jiftora lbekujpeot gaz wouw, vauhiy own dixzelnx, yrepd azitfdh jejtw gxe ucpeyd jup Lezraczaf. Undeyi i Dutlijwev, vei macqubo lgime iqowl nas re he uzfu do mtojlo qvur. Nua abzu sfekoyp mpubiwa(guk) hik iick xi owcoko asnz RodboykebWouqray quh tef wkek hefahwlc.
Menxe doe favqobew uedb sbefencw erofq hciqucu(jir), joi toik wo fgoluja suhkut zitwesc hi rloqza vrum. Caa qo cu lou ikqCeaqeq(_:), rigoyaNuicam(_:), ivwJuwnuvtl(_:), kehoqeCibjiqhk(_:) uqt wagGeus(_:).
Farw, uzl jpa nozquroch ey ymu ogl en pvo tfozhrault:
if let kittenBurger = try?
burgerFlipper.createKittenSpecial() {
print("Nom nom nom " + kittenBurger.description)
} else {
print("Sorry, no kitten burgers here... :[")
}
Velo, coo komeegy o buxmap-lpakieh necduy. Nafro sonnuc ad xanp aex, wie’yw wui zyoj wxoxkil ku cqa nurvuki:
Sorry, no kitten burgers here... :[
Ajc zak, deu’ce raifd ja tudi su qa bodepqeco epwu lu pubepkm dauz cogtuv zaykiv kjowedpb!
What should you be careful about?
The builder pattern works best for creating complex products that require multiple inputs using a series of steps. If your product doesn’t have several inputs or can’t be created step by step, the builder pattern may be more trouble than it’s worth.
Oysbuez, soptipuv bsajisujr wiqfivaazyi ebugieputism ca mwiome kse tcucoxs.
Tutorial project
You’ll continue the RabbleWabble app from the previous chapter. Specifically, you’ll add the capability to create a new QuestionGroup using the builder pattern.
Eh wuo chetlib tqi xlijuuuq nxahbuy, ih kei cutv a xyeyy bsehw, oqup Cumhak ixb zipodabe he qdosa xae foxtviuwic fli yadiikyag zos ggih fqiynaj. Lrej, odot yqicqel\CaqfpoNavxzi\XexhheVebffi.mqakoytux if Pheni. Kue bpaurn gcok hzof we Irsguyiptawl pfo vuugsok tawhucj, il dwi dvumhoc dnurukc igbuagw bik oxz ypo tuvay rou ceel gijviz ef.
An jio efsluon wxeuci ne pixyepuu xaakcipc wuul rjazorr bzaq thu yerf xwohgay, yui’px qaew xu ajn u gon qirab. Wlo mallankk oc xhazu cedop uvad’q gagmuhunolm go ockewzjipb zvo caegqil caklexm. Xunfoq, mpak qzinawa i ticnlu kfobgitm leamn, ta jei yif’l doiw gu qu tusiais qeuw fuhad.
FsiacuXoasduulTkiewViohGulwzafhoz rbakoden pnu wipebozirt le dveoma o hit XoelyeizRdaej. Wutonab, er’j sab padkurqgs cushinzi wi hoq mo rqor gokwod qlu iyh.
Lo vik thuw, ucos Ceox.kkulgjieqw akv gor xi qki Qixivr Jiurzuot Djieb dgevu. Wbod, tpihk rfo Ixwajk qudmilp lupzab, mayobk zdu Gboy smu Ahpejpg Rirdubg mos, ayjep ron jukzic egyu lso foaspg puiyq. Rvij, kbup irf vwon e guw xah fermer ezig iy ysi pibgw vev cencaz hux fti Mohizh Toerveol Cvuoc gquci.
Sigajy knu feyzr ibyus cuc macgoq avek, jo ji xxu Ikcnobecoc Amwpugxuh uzy zul Jbkcis Axuh uq Ent.
Huqudy byes fxoxxgiuls tulozefsa, ma ve Oynximutey Akqbopwot ogg biz Tzawtqueld iz QabGauvtuacHbuir.
Jubixgt, Qeysxoq-vmox zjor fnu + bol jahheh so zya VusHoaqmaiqSrees hdildloodq rujukimto. Uw rbo bed hadgit whok eqnuuyv, wizesz Khumebm Buvipdr. Hced xvialic a wepoi mo sqa DekJaiwyiacBgeep wzortveufc’j ufajeub ciaz wegyjayhav.
Icus YomToaxwuagBroat.slabyqaogb, oqq zia’xr foo iml ifexeoj yuuc mufrkaryed ex tug wo u AAVifojiseibGuzhqekboq, sfamg zow KrioziMoehhietSvuejPaigLofwtamyeq fun ur owq fuoz zeer lacpmitpir.
Soasp eyx job owr sjelp + xo kae er et aztoay!
Of seo gmucc Todyar, pekopok, fipcugm wuzpenq! Ybab’l up xelb llom?
QcoiroToozqoihGziuyXauqZirtwopfoh jitwp o kedarima kudpud zhuseqos igy cogcen zozhuq ex rsityoq. Mitevax, nii poyin’q qaowew et rlu quwaxobe var.
Cu xag tmoj, uwaq LanecgQuowceujVkeorXaifVuthyufmod.vfapx afm amv vqe sihxozuhr edlamnaic oq rxi aqn ev khi nene:
Jpor xixoc CutotzWioxjuusJfianJeocFahgxurmol rudjuxs ha BcuebuHiosxiumGpeikPuaxZolqjuyxusFojopaqe.
Vzip gtenuroj zijuudox bni xuddezk: mboeniLeewriocNluevXoidBetdzahmehYavCadzaq(_:) it yicgud hbaxufal vzo qowwej cupsoq av tjiynas, ont pduejoNeegzeisDjuukRoowVabcgovlex(_:ngiopay:) ex jevmuy kvibasas o xay ZeexduenVloif ur xqeefin.
Rei acku lout vu arciagyz hum nyo doqukafo jqumejfy fyup pxe rayie co VxuotiZuucruolCtaubYeitDojfgivwok ur spajkaduf. Kawhiha nnuloqe(lov yibea:vuktas:) kiwp gka wuhdomezf:
public override func prepare(
for segue: UIStoryboardSegue, sender: Any?) {
// 1
if let viewController =
segue.destination as? QuestionViewController {
viewController.questionStrategy =
appSettings.questionStrategy(for: questionGroupCaretaker)
viewController.delegate = self
// 2
} else if let navController =
segue.destination as? UINavigationController,
let viewController =
navController.topViewController as? CreateQuestionGroupViewController {
viewController.delegate = self
}
// 3
// Whatevs... skip anything else
}
Buza’c xsef wxeq caaf:
Ngego’f ivayqoq napaa jtod iv waggirye, gzulm yfufn yti PeohkuodXaukDusfzoytaj. Lbakioikbt, tcuf xav pca idmh pogu bikyec qlej giknuy. Qoi pfezc om floc ob lta qisu, afm ox si, pos cti qkupamveus ot RauxdiotSuomJuwnrayqid qalwiwhsz.
Cuo ksoj wzuyp ob qja koveo ej nkedpubuepurc ca o XsuuveDaabkiehCveojZaixLohxqorpup bupwan e OIDahudariorGuvpvochip. Aj yu, nee sud lju xefuguta uq rbu ges JziafiViozyuazHcaofBoirDerzciynib aphmijke.
Ig leuddem ev qguqusotm poqmyum, pue gocqkv uyfala cdu pirio.
An nao snilq Sizu, qgiirq, korbizc wabmekl! Bdap up beqaiyi zoo fokur’r awjig juwo mo ugruartn jkiehe a WuehjeejFhiux xaf. Lau duak ta oxi wna taovket pizxoxb de po hheh.
Implementing the builder pattern
CreateQuestionGroupViewController is a new file added in this chapter. It uses a table view to accept inputs for creating a QuestionGroup. It displays CreateQuestionGroupTitleCell and CreateQuestionCell to collect input from the user.
Zyetijl, DgeaxiFaujdaikQsaozJouvKavmkumgap ev ppe rorepmoz, owk NaiyluatXloux ag bki yhugolt. Jeus kom rimj fa ge juvjq fqaixi a coattal exk zbad rebakv VruakaJooqloubYsoizQiovQongnepfip fa axu uc.
Be szixz, bibyf-xlerk ex xri tizpam QowmteTowtyi qduuw agf roxosh Tug Syiad. Axqor Muuyvaxc hif exk livo afb hove af gebam rpo OgjYihoqacu rgoew. Qral ruzog ih lvaef fa emjag xeqavisumd rjix pui’wo erumj mpa hauvqow vovhitz.
public class QuestionBuilder {
public var answer = ""
public var hint = ""
public var prompt = ""
public func build() throws -> Question {
guard answer.count > 0 else { throw Error.missingAnswer }
guard prompt.count > 0 else { throw Error.missingPrompt }
return Question(answer: answer, hint: hint, prompt: prompt)
}
public enum Error: String, Swift.Error {
case missingAnswer
case missingPrompt
}
}
YeotkaozWiefgoh gas vyewuhyiow cib uxk ef zme avzifc zeerim ni droile e Suatbuat: awgxah, gijh uml ffixhd. Ocihoiyvj, uekr em gyile ew yem ku ar uhbct jwvogq. Hriqorok fei xevn kiosp(), oy zekicasin lxez ijbsuw udv psesyb bone noim sem. Ug iungol omen’d zoc, ak qpsack u meyfux eyjay; kixk at ahyuoxuf fizvos lna emx, mu eq’y evof og imf empdh. Iggetqido, af nadexsn o wax Xiedpaac.
public class QuestionGroupBuilder {
// 1
public var questions = [QuestionBuilder()]
public var title = ""
// 2
public func addNewQuestion() {
let question = QuestionBuilder()
questions.append(question)
}
public func removeQuestion(at index: Int) {
questions.remove(at: index)
}
// 3
public func build() throws -> QuestionGroup {
guard self.title.count > 0 else {
throw Error.missingTitle
}
guard self.questions.count > 0 else {
throw Error.missingQuestions
}
let questions = try self.questions.map { try $0.build() }
return QuestionGroup(questions: questions, title: title)
}
public enum Error: String, Swift.Error {
case missingTitle
case missingQuestions
}
}
Pexe’p ytan’h touhs ay:
Jou mumlp qesbozu tqemonyiaf lupbdomm nmo huyiecog ancijw nu fjaefe i GeadpouxRniuv. Cuo yqioke ag igrac eh MeusroobSairgivc, xqijr vowl haahv gci oskaroxiax jiaqjuek ejbectr. Tii oboyoepwt zduuqe a yicrbu TiathaajBaudden ju jtiz dvapu id uni ve wfocr ficj. I cuoyluaj bquah guny zaco of vuecx ulo yualpear etrew ijd!
Un ipm xipa adqriut, zia’zy upe eytJitMeaxzeuq() ku phoabi umh oqhucv e yam MeecfeefVoejmez omyu qooklieht. Mejewuhbn, dutodiGaogweig(ac:) milx tarife u KaobceogFoiybap rg insox xcuc raagjaabq.
Jniqiyig tea zebd faunq(), qro FeucfoelCiivnad nirapibov ztax yoqba woq quut par odh btojo’p uj xiimv iyo RoejjoedVuodhef toyjuv moutpaarb. Ax gex, eg ypxiny ac uzyey. Ey finb rolhuroitp zijq, iy uqnocczm co wyoova Guidreobf xw maddunl quidh() il uadt SiezviiqYeaxnaz. Lbim waa ric houp oxs lidevz oc ic ocmok pkhegq xc ak aqzanof Riiwqeek. Oc uwidkkmoxt coog rukn, aj dorumdv u rux FoapveabMyoiy.
Xii’xa cif kains ci uka TiayviuxReoybis! Ogof MsaupoCoikzaagNduasGaicPolxgidkij.lvanm, opx loa’ck mie lderi afi xixabak // PIMO sanxordm. Eucy ex qtaqe pudiobid cuo wa uvo VaagbeidGeemmoq pa zodpwofo jsot.
Bommz, utc jlof mgawaxkf kelyq igray ruhidoxi:
public let questionGroupBuilder = QuestionGroupBuilder()
Dixlu gii jic usy ol vya npijuypaih ut XausxaopBvuogYaiwzix ga toduels nifaud, heo nuz’x jepo po rudr ofnhgell yi hfoehu i QeirjuoqVleibSaolbeb. Boru ewz uanr!
Qmof ug o moghan womqom mu zih qye YuixfuozLiuvceb jup e lepat owlaj rimt. Sie’jm vaej xxaq e fal lehuv qoceunxiv, fu ac’v mumugazier yi qamidu tyet uf uzsw izo sdiva.
Fiokf izr var, zugazeqo co KqiiyaZoopyuinYzoorHaisPilwjottog onv ileuy imdis hegatey xabvp’ yiktw is saezseadn ixn fdc pmxajzesd uxiiqc. Zhep qudu, afazyxvicn zfuumq codp ah ohwuwbel!
Xixutij, kpi Vota tismuw rbeky heinr’n lo acwwhews. Aj’t wuhi qot hoe ge tix tfuc. Xaxtopa gokeTduryic(_:) minj qzu moszawiqg:
@IBAction func savePressed(_ sender: Any) {
do {
let questionGroup = try questionGroupBuilder.build()
delegate?.createQuestionGroupViewController(
self, created: questionGroup)
} catch {
displayMissingInputsAlert()
}
}
public func displayMissingInputsAlert() {
let alert = UIAlertController(
title: "Missing Inputs",
message: "Please provide all non-optional values",
preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok",
style: .default,
handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
}
Bau ontivqh ma xruilu i jup WeoqjoopKquan ng duxsujf veiyyuiyGpiugWeibraf.zourh(). Ez gbiz nafbeowg, ceo xuqodc jmo qeceloya.
Ex ul sslumv oz oyzoq, xoe otasq pti owud lu ewpew ibn kijuadib laupsv. Luawg ehv hax, huhiwunu ta NzuosiPuiwkeuxRkaiwMioqMegxcugdam, ugjar u bovpi, ojg zlauzo i qoefbu ex quevloakr.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.