Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork158
💎 The Principles of OOD (SOLID) based on Uncle Bob articles.
License
ochococo/OOD-Principles-In-Swift
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A short cheat-sheet with Playground (OOD-Principles-In-Swift.playground.zip).
👷 Project maintained by:@nsmeme (Oktawian Chojnacki)
🇰🇷 Korean:README-ko-KR.md
- The Single Responsibility Principle
- The Open Closed Principle
- The Liskov Substitution Principle
- The Interface Segregation Principle
- The Dependency Inversion Principle
A class should have one, and only one, reason to change. (read more)
Example:
protocolOpenable{mutatingfunc open()}protocolCloseable{mutatingfunc close()}// I'm the door. I have an encapsulated state and you can change it using methods.structPodBayDoor:Openable,Closeable{privateenumState{case opencase closed}privatevarstate:State=.closedmutatingfunc open(){ state=.open}mutatingfunc close(){ state=.closed}}// I'm only responsible for opening, no idea what's inside or how to close.finalclassDoorOpener{privatevardoor:Openableinit(door:Openable){self.door= door}func execute(){ door.open()}}// I'm only responsible for closing, no idea what's inside or how to open.finalclassDoorCloser{privatevardoor:Closeableinit(door:Closeable){self.door= door}func execute(){ door.close()}}letdoor=PodBayDoor() // ⚠️ Only the `DoorOpener` is responsible for opening the door.letdoorOpener=DoorOpener(door: door)doorOpener.execute()// ⚠️ If another operation should be made upon closing the door,// like switching on the alarm, you don't have to change the `DoorOpener` class.letdoorCloser=DoorCloser(door: door)doorCloser.execute()
You should be able to extend a classes behavior, without modifying it. (read more)
Example:
protocolShooting{func shoot()->String}// I'm a laser beam. I can shoot.finalclassLaserBeam:Shooting{func shoot()->String{return"Ziiiiiip!"}}// I have weapons and trust me I can fire them all at once. Boom! Boom! Boom!finalclassWeaponsComposite{letweapons:[Shooting]init(weapons:[Shooting]){self.weapons= weapons}func shoot()->[String]{return weapons.map{ $0.shoot()}}}letlaser=LaserBeam()varweapons=WeaponsComposite(weapons:[laser])weapons.shoot()// I'm a rocket launcher. I can shoot a rocket.// ⚠️ To add rocket launcher support I don't need to change anything in existing classes.finalclassRocketLauncher:Shooting{func shoot()->String{return"Whoosh!"}}letrocket=RocketLauncher()weapons=WeaponsComposite(weapons:[laser, rocket])weapons.shoot()
Derived classes must be substitutable for their base classes. (read more)
Example:
letrequestKey:String="NSURLRequestKey"// I'm a NSError subclass. I provide additional functionality but don't mess with original ones.classRequestError:NSError{varrequest:NSURLRequest?{returnself.userInfo[requestKey]as?NSURLRequest}}// I fail to fetch data and will return RequestError.func fetchData(request:NSURLRequest)->(data:NSData?, error:RequestError?){letuserInfo:[String:Any]=[requestKey: request]return(nil,RequestError(domain:"DOMAIN", code:0, userInfo: userInfo))}// I don't know what RequestError is and will fail and return a NSError.func willReturnObjectOrError()->(object:AnyObject?, error:NSError?){letrequest=NSURLRequest()letresult=fetchData(request: request)return(result.data, result.error)}letresult=willReturnObjectOrError()// Ok. This is a perfect NSError instance from my perspective.leterror:Int?= result.error?.code// ⚠️ But hey! What's that? It's also a RequestError! Nice!iflet requestError= result.erroras?RequestError{ requestError.request}
Make fine grained interfaces that are client specific. (read more)
Example:
// I have a landing site.protocolLandingSiteHaving{varlandingSite:String{get}}// I can land on LandingSiteHaving objects.protocolLanding{func land(on:LandingSiteHaving)->String}// I have payload.protocolPayloadHaving{varpayload:String{get}}// I can fetch payload from vehicle (ex. via Canadarm).protocolPayloadFetching{func fetchPayload(vehicle:PayloadHaving)->String}finalclassInternationalSpaceStation:PayloadFetching{ // ⚠ Space station has no idea about landing capabilities of SpaceXCRS8.func fetchPayload(vehicle:PayloadHaving)->String{return"Deployed\(vehicle.payload) at April 10, 2016, 11:23 UTC"}}// I'm a barge - I have landing site (well, you get the idea).finalclassOfCourseIStillLoveYouBarge:LandingSiteHaving{letlandingSite="a barge on the Atlantic Ocean"}// I have payload and can land on things having landing site.// I'm a very limited Space Vehicle, I know.finalclassSpaceXCRS8:Landing,PayloadHaving{letpayload="BEAM and some Cube Sats" // ⚠️ CRS8 knows only about the landing site information.func land(on:LandingSiteHaving)->String{return"Landed on\(on.landingSite) at April 8, 2016 20:52 UTC"}}letcrs8=SpaceXCRS8()letbarge=OfCourseIStillLoveYouBarge()letspaceStation=InternationalSpaceStation()spaceStation.fetchPayload(vehicle: crs8)crs8.land(on: barge)
Depend on abstractions, not on concretions. (read more)
Example:
protocolTimeTraveling{func travelInTime(time:TimeInterval)->String}finalclassDeLorean:TimeTraveling{func travelInTime(time:TimeInterval)->String{return"Used Flux Capacitor and travelled in time by:\(time)s"}}finalclassEmmettBrown{privatelettimeMachine:TimeTraveling // ⚠️ Emmet Brown is given a `TimeTraveling` device, not the concrete class `DeLorean`!init(timeMachine:TimeTraveling){self.timeMachine= timeMachine}func travelInTime(time:TimeInterval)->String{return timeMachine.travelInTime(time: time)}}lettimeMachine=DeLorean()letmastermind=EmmettBrown(timeMachine: timeMachine)mastermind.travelInTime(time:-3600*8760)
📖 Descriptions from:The Principles of OOD by Uncle Bob
About
💎 The Principles of OOD (SOLID) based on Uncle Bob articles.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors4
Uh oh!
There was an error while loading.Please reload this page.