You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+200Lines changed: 200 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4047,3 +4047,203 @@ Summary:
4047
4047
4048
4048
When you are in a situation to build a template/ base class which is open for extension but closed for modification, or in simple words, subclasses should be able to extend the base algorithm without altering its structure, Template design patterns suits the best.
4049
4049
4050
+
**28) Behavioral - Visitor Design Pattern:**
4051
+
4052
+
Definition:
4053
+
4054
+
Visitor is a behavioral design pattern that lets us define a new operation without changing the classes of the objects on which it operates. We use it when we do not want to keep modifying every class in the hierarchy.
4055
+
4056
+
Usage:
4057
+
4058
+
Consider a situation where we are designing a checkout counter in a shop that sells cricket accessories. It offers discount on selective brands and selective items. Let us see how we can use Visitor pattern to design such system.
4059
+
4060
+
```
4061
+
import Foundation
4062
+
import UIKit
4063
+
4064
+
protocol CricketAccessory{
4065
+
func accept(counter : CheckoutCounter) -> Int
4066
+
}
4067
+
```
4068
+
4069
+
We define a protocol called CricketAccessory with a function called accept which takes a parameter of type CheckoutCounter ( to be defined) and returns an integer.
4070
+
4071
+
```
4072
+
class CricketBat : CricketAccessory{
4073
+
private var price : Double
4074
+
private var brand : String
4075
+
4076
+
init(_ price : Double, _ brand:String) {
4077
+
self.price = price
4078
+
self.brand = brand
4079
+
}
4080
+
4081
+
public func getPrice() -> Double{
4082
+
return price
4083
+
}
4084
+
4085
+
public func getBrand() -> String{
4086
+
return brand
4087
+
}
4088
+
func accept(counter : CheckoutCounter) -> Int {
4089
+
return counter.moveToCounter(bat: self)
4090
+
}
4091
+
}
4092
+
```
4093
+
4094
+
We then define a class called CricketBat conforming to CricketAccessory protocol. It has two private variables defined namely, price of type Double and brand of type String. We also two define two public methods called getPrice and getBrand to return price and brand of the bat respectively.
4095
+
4096
+
```
4097
+
class CricketBall : CricketAccessory{
4098
+
4099
+
private var type : String
4100
+
private var price : Double
4101
+
4102
+
init(_ type : String, _ price : Double){
4103
+
self.type = type
4104
+
self.price = price
4105
+
4106
+
}
4107
+
4108
+
public func getType() -> String{
4109
+
return type
4110
+
}
4111
+
4112
+
public func getPrice() -> Double{
4113
+
return price
4114
+
}
4115
+
4116
+
func accept(counter : CheckoutCounter) -> Int {
4117
+
return counter.moveToCounter(ball: self)
4118
+
}
4119
+
4120
+
}
4121
+
4122
+
```
4123
+
4124
+
We define another class called CricketBall conforming to CricketAccessory protocol. This is very much similar to CricketBat class.
4125
+
4126
+
```
4127
+
protocol CheckoutCounter {
4128
+
func moveToCounter(bat : CricketBat) -> Int
4129
+
func moveToCounter(ball : CricketBall) -> Int
4130
+
}
4131
+
4132
+
```
4133
+
4134
+
We define a protocol called CheckoutCounter which has two methods with the same name but differs when it comes to parameter types.
4135
+
4136
+
```
4137
+
class CashCounter :CheckoutCounter{
4138
+
func moveToCounter(bat: CricketBat) -> Int {
4139
+
var cost : Int = 0
4140
+
if bat.getBrand() == "MRF"{
4141
+
cost = Int(0.9 * bat.getPrice())
4142
+
} else{
4143
+
cost = Int(bat.getPrice())
4144
+
}
4145
+
print("Bat brand : \(bat.getBrand()) and price is : \(cost) ")
4146
+
return cost
4147
+
}
4148
+
4149
+
func moveToCounter(ball: CricketBall) -> Int {
4150
+
4151
+
print("Ball Type : \(ball.getType()) and price is : \(ball.getPrice()) ")
4152
+
return Int(ball.getPrice())
4153
+
}
4154
+
}
4155
+
4156
+
```
4157
+
4158
+
We now define a class called CashCounter conforming to CheckoutCounter. We can see that, for a cricket bat of brand MRF we give a discount of 10%. In future, if we want to add any new brands or remove discount on existing brands, we can make all the changes here with no changes required at the client end.
4159
+
Let us now write main function to see the code in action:
var cost = finalPriceCalculation(accessories: cartItems)
4184
+
print("Checked Out with Bill Amount : \(cost)")
4185
+
}
4186
+
4187
+
main()
4188
+
```
4189
+
4190
+
We define a function called finalPriceCalculation which takes an array of type CricketAccessory and returns the final cart value.
4191
+
4192
+
Output in the Xcode console:
4193
+
4194
+
Main
4195
+
Bat brand : MRF and price is : 1800
4196
+
Bat brand : Brittania and price is : 1500
4197
+
Ball Type : Tennis and price is : 120.0
4198
+
Ball Type : Leather and price is : 200.0
4199
+
Total cart value : 3620
4200
+
Checked Out with Bill Amount : 3620
4201
+
4202
+
You can see MRF bat is checkout at discounted price.
4203
+
4204
+
Let us now change the CashCounter class to following:
4205
+
4206
+
```
4207
+
class CashCounter :CheckoutCounter{
4208
+
func moveToCounter(bat: CricketBat) -> Int {
4209
+
var cost : Int = 0
4210
+
if bat.getBrand() == "Brittania"{
4211
+
cost = Int(0.8 * bat.getPrice())
4212
+
} else{
4213
+
cost = Int(bat.getPrice())
4214
+
}
4215
+
print("Bat brand : \(bat.getBrand()) and price is : \(cost) ")
4216
+
return cost
4217
+
}
4218
+
4219
+
func moveToCounter(ball: CricketBall) -> Int {
4220
+
4221
+
print("Ball Type : \(ball.getType()) and price is : \(ball.getPrice()) ")
4222
+
return Int(ball.getPrice())
4223
+
}
4224
+
}
4225
+
```
4226
+
4227
+
Now, we are removing discount on MRF and giving 20% discount on Brittania bats.
4228
+
4229
+
The same main method gives a different output in the Xcode console:
4230
+
4231
+
Main
4232
+
Bat brand : MRF and price is : 2000
4233
+
Bat brand : Brittania and price is : 1200
4234
+
Ball Type : Tennis and price is : 120.0
4235
+
Ball Type : Leather and price is : 200.0
4236
+
Total cart value : 3520
4237
+
Checked Out with Bill Amount : 3520
4238
+
4239
+
Summary:
4240
+
4241
+
When you are in a situation where you might want to add a new action and have that new action entirely defined within one of the visitor classes rather than spread out across multiple classes, Visitor design pattern serves you the best.
4242
+
4243
+
**Final Note: **
4244
+
4245
+
4246
+
It is not necessary to learn all the patterns and their applications by heart. The main intention is to identify the use-cases and problems which the design patterns are meant to address. Then applying a specific design pattern is just a matter of using right tool at right time for the right job. It's the job that must be identified and understood before the tool can be chosen.
0 commit comments